// Converts 3MF files to GLB via the Python/trimesh sidecar, so the browser can // render Bambu/MakerWorld production-extension 3MFs (which the JS 3MFLoader can't), // and reads their slicer project details (plates, filaments). const { runScript } = require('./python'); // Parses a sidecar script's last JSON line, turning its error / failure into a throw. function parseResult({ err, stdout, stderr }, what) { let result = null; try { result = JSON.parse(stdout.trim().split('\n').pop()); } catch { /* handled below */ } if (result && result.error) throw new Error(result.error); if (err) { if (err.killed) throw new Error(`Timed out ${what}.`); throw new Error(stderr ? stderr.trim().split('\n').slice(-3).join(' ') : err.message); } if (!result) throw new Error(`Unparseable output ${what}.`); return result; } // Returns { glb, plate, volume_cm3, bbox, faces } or throws. `plate` limits the // output to one plate of a slicer project. async function convert3mfToGlb(inputPath, outputPath, { plate = null } = {}) { const args = [inputPath, outputPath]; if (plate) args.push('--plate', String(plate)); return parseResult(await runScript('convert_3mf.py', args, { timeout: 120000 }), 'converting this 3MF for preview'); } // Returns { plates: [{ index, name, objectCount, thumbnail }], filaments: [{ colour, type }] }. // Plate previews are written into imagesDir as .png / -small.png. async function readProjectInfo(inputPath, imagesDir) { return parseResult(await runScript('threemf_info.py', [inputPath, '--images', imagesDir], { timeout: 60000 }), 'reading this 3MF project'); } // Just the filaments a project asks for: no --images, so no plate previews are // written, and queued behind anything someone is waiting on — this runs over the // whole library in the background. async function readFilaments(inputPath) { const info = await parseResult( await runScript('threemf_info.py', [inputPath], { timeout: 60000, isBackground: true }), 'reading this 3MF project'); return Array.isArray(info.filaments) ? info.filaments : []; } module.exports = { convert3mfToGlb, readProjectInfo, readFilaments };