← back to Wallpaper Tour
preflight.mjs
67 lines
#!/usr/bin/env node
// Pre-flight: HEAD each https://<name>.com with 8s timeout, keep live ones.
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const projects = fs.readFileSync(path.join(__dirname, 'projects.txt'), 'utf8')
.split('\n').map(s => s.trim()).filter(Boolean);
const TIMEOUT_MS = 8000;
async function checkUrl(name) {
const url = `https://${name}.com`;
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), TIMEOUT_MS);
try {
// Try HEAD first; some servers reject HEAD, fall back to GET range
let res;
try {
res = await fetch(url, { method: 'HEAD', redirect: 'follow', signal: ctrl.signal });
} catch (_) {
res = await fetch(url, { method: 'GET', redirect: 'follow', signal: ctrl.signal, headers: { Range: 'bytes=0-1023' } });
}
clearTimeout(timer);
if (res.status >= 200 && res.status < 400) {
return { name, url: res.url || url, status: res.status, live: true };
}
// 405 (method not allowed) usually means HEAD-rejected — try GET
if (res.status === 405) {
const ctrl2 = new AbortController();
const t2 = setTimeout(() => ctrl2.abort(), TIMEOUT_MS);
try {
const r2 = await fetch(url, { method: 'GET', redirect: 'follow', signal: ctrl2.signal });
clearTimeout(t2);
if (r2.status >= 200 && r2.status < 400) return { name, url: r2.url || url, status: r2.status, live: true };
return { name, url, status: r2.status, live: false };
} catch (e) {
clearTimeout(t2);
return { name, url, status: 0, live: false, error: e.message };
}
}
return { name, url, status: res.status, live: false };
} catch (e) {
clearTimeout(timer);
return { name, url, status: 0, live: false, error: e.message };
}
}
const results = [];
// Sequential to be gentle (Steve says load avg ~500)
let i = 0;
for (const name of projects) {
i++;
process.stdout.write(`[${i}/${projects.length}] ${name} ... `);
const r = await checkUrl(name);
results.push(r);
console.log(r.live ? `LIVE (${r.status})` : `DEAD (${r.status}${r.error ? ' ' + r.error : ''})`);
}
const live = results.filter(r => r.live);
fs.writeFileSync(path.join(__dirname, 'live-urls.txt'), live.map(r => `${r.name}\t${r.url}`).join('\n') + '\n');
fs.writeFileSync(path.join(__dirname, 'preflight-results.json'), JSON.stringify(results, null, 2));
console.log(`\nLIVE: ${live.length}/${results.length}`);
console.log(`Wrote ${path.join(__dirname, 'live-urls.txt')}`);