84 lines
2.2 KiB
JavaScript
84 lines
2.2 KiB
JavaScript
const candidates = [
|
|
"https://raw.githubusercontent.com/richaude/blue-book/master/scrubbed.csv",
|
|
"https://raw.githubusercontent.com/alecfirrincieli/UFO-sightings/main/ufo-sightings.csv",
|
|
];
|
|
|
|
let csvText = null;
|
|
for (const url of candidates) {
|
|
try {
|
|
const response = await fetch(url);
|
|
if (!response.ok) continue;
|
|
const text = await response.text();
|
|
if (text && text.includes("datetime,city,state")) {
|
|
csvText = text;
|
|
break;
|
|
}
|
|
} catch {}
|
|
}
|
|
|
|
if (!csvText) {
|
|
throw new Error("Unable to fetch UFO sightings dataset from public mirrors.");
|
|
}
|
|
|
|
const { csvParse } = await import("d3-dsv");
|
|
const rows = csvParse(csvText);
|
|
|
|
const normalizeKey = (value) =>
|
|
String(value ?? "")
|
|
.trim()
|
|
.toLowerCase();
|
|
|
|
function readField(row, key) {
|
|
const target = normalizeKey(key);
|
|
for (const [field, value] of Object.entries(row)) {
|
|
if (normalizeKey(field) === target) return value;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
function parseNumber(value) {
|
|
const parsed = Number(value);
|
|
return Number.isFinite(parsed) ? parsed : null;
|
|
}
|
|
|
|
const ufo = rows
|
|
.map((row, index) => {
|
|
const state = String(readField(row, "state") ?? "")
|
|
.trim()
|
|
.toLowerCase();
|
|
const country = String(readField(row, "country") ?? "")
|
|
.trim()
|
|
.toLowerCase();
|
|
const latitude = parseNumber(readField(row, "latitude"));
|
|
const longitude = parseNumber(readField(row, "longitude"));
|
|
|
|
if (state !== "ca" || country !== "us") return null;
|
|
if (latitude === null || longitude === null) return null;
|
|
|
|
const inCaliforniaBounds =
|
|
latitude >= 32 &&
|
|
latitude <= 42.5 &&
|
|
longitude >= -125 &&
|
|
longitude <= -114;
|
|
|
|
if (!inCaliforniaBounds) return null;
|
|
|
|
const durationSeconds =
|
|
parseNumber(readField(row, "duration (seconds)")) ?? 0;
|
|
|
|
return {
|
|
id: `ufo/${index}`,
|
|
datetime: readField(row, "datetime") ?? null,
|
|
city: readField(row, "city") ?? "Unknown",
|
|
state,
|
|
shape: String(readField(row, "shape") ?? "unknown").toLowerCase(),
|
|
durationSeconds,
|
|
comments: readField(row, "comments") ?? "",
|
|
latitude,
|
|
longitude,
|
|
};
|
|
})
|
|
.filter(Boolean);
|
|
|
|
process.stdout.write(JSON.stringify(ufo));
|