Files
micromelon-website/scripts/download-sqsp-images.mjs
Tim Hadwen ae3ae18585 Major site overhaul: resources hub, content migration, new blog posts, forms
- Redesign /resources as sectioned hub with category pages
- Migrate 645 Squarespace CDN images to local /images/content/
- Create 9 new news/blog posts with event photos
- Fix blog post slugs (rename gibberish filenames)
- Rename Design Blog to Design Blogs across site
- Remove education page, replace with Platform in nav
- Redesign rover repair request form with dynamic rover entries
- Add school search combobox to contact, store, and repair forms
- Extract shared KNOWN_SCHOOLS data
- Make /rover-expansion-3d-printing dynamically pull from MDX
- Add related resources sections to product pages
- Fix homepage broken /quote links to /store
- Store page: sample kit cards, inline quote builder, mailing list opt-in
2026-03-01 17:14:05 +10:00

106 lines
2.9 KiB
JavaScript

import fs from "fs";
import path from "path";
import { execSync } from "child_process";
import crypto from "crypto";
const RESOURCES_DIR = "content/resources";
const IMAGES_DIR = "public/images/resources/content";
// Collect all unique Squarespace URLs from MDX files
const mdxFiles = fs.readdirSync(RESOURCES_DIR).filter((f) => f.endsWith(".mdx"));
const urlMap = new Map(); // url -> local filename
let totalUrls = 0;
for (const file of mdxFiles) {
const content = fs.readFileSync(path.join(RESOURCES_DIR, file), "utf8");
const urls = content.match(/https:\/\/images\.squarespace-cdn\.com\/[^\s"'\)]+/g);
if (urls) {
for (const url of urls) {
if (!urlMap.has(url)) {
// Generate a short filename from the URL
const urlPath = new URL(url).pathname;
const ext = path.extname(urlPath).toLowerCase() || ".jpg";
const baseName = path.basename(urlPath, ext).replace(/[^a-zA-Z0-9_-]/g, "-").substring(0, 60);
const hash = crypto.createHash("md5").update(url).digest("hex").substring(0, 8);
const localName = `${baseName}-${hash}${ext}`;
urlMap.set(url, localName);
totalUrls++;
}
}
}
}
console.log(`Found ${totalUrls} unique Squarespace URLs across ${mdxFiles.length} MDX files`);
// Download all images
let downloaded = 0;
let failed = 0;
const failedUrls = [];
for (const [url, localName] of urlMap) {
const localPath = path.join(IMAGES_DIR, localName);
if (fs.existsSync(localPath) && fs.statSync(localPath).size > 1000) {
downloaded++;
continue;
}
try {
execSync(
`curl -sL -o "${localPath}" --max-time 30 "${url}"`,
{ timeout: 35000 }
);
const stat = fs.statSync(localPath);
if (stat.size < 500) {
console.log(`WARN: Small file (${stat.size}b) for ${url}`);
fs.unlinkSync(localPath);
failed++;
failedUrls.push(url);
} else {
downloaded++;
}
} catch (e) {
console.log(`FAIL: ${url}`);
failed++;
failedUrls.push(url);
if (fs.existsSync(localPath)) fs.unlinkSync(localPath);
}
if ((downloaded + failed) % 50 === 0) {
console.log(`Progress: ${downloaded + failed}/${totalUrls} (${failed} failed)`);
}
}
console.log(`\nDownloaded: ${downloaded}, Failed: ${failed}`);
// Rewrite MDX files
let filesUpdated = 0;
for (const file of mdxFiles) {
const filePath = path.join(RESOURCES_DIR, file);
let content = fs.readFileSync(filePath, "utf8");
let changed = false;
for (const [url, localName] of urlMap) {
if (content.includes(url)) {
const localRef = `/images/resources/content/${localName}`;
content = content.replaceAll(url, localRef);
changed = true;
}
}
if (changed) {
fs.writeFileSync(filePath, content);
filesUpdated++;
}
}
console.log(`Updated ${filesUpdated} MDX files`);
if (failedUrls.length > 0) {
console.log(`\nFailed URLs:`);
for (const u of failedUrls) {
console.log(` ${u}`);
}
}