119 lines
3.5 KiB
JavaScript
119 lines
3.5 KiB
JavaScript
const query = `
|
|
[out:json][timeout:120];
|
|
area["ISO3166-2"="US-CA"][admin_level=4]->.searchArea;
|
|
(
|
|
node["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
|
|
way["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
|
|
relation["amenity"="fast_food"]["brand"="In-N-Out Burger"](area.searchArea);
|
|
node["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
|
|
way["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
|
|
relation["amenity"="fast_food"]["name"~"In-N-Out",i](area.searchArea);
|
|
);
|
|
out center tags;
|
|
`;
|
|
|
|
function normalizeStores(elements) {
|
|
const stores = elements
|
|
.map((element) => {
|
|
const lat = Number(element.lat ?? element.center?.lat);
|
|
const lon = Number(element.lon ?? element.center?.lon);
|
|
if (!Number.isFinite(lat) || !Number.isFinite(lon)) return null;
|
|
|
|
const tags = element.tags ?? {};
|
|
const name = tags.name || "In-N-Out Burger";
|
|
const city = tags["addr:city"] || "Ville inconnue";
|
|
const street = tags["addr:street"] || "";
|
|
const housenumber = tags["addr:housenumber"] || "";
|
|
const postcode = tags["addr:postcode"] || "";
|
|
|
|
return {
|
|
id: `${element.type}/${element.id}`,
|
|
latitude: lat,
|
|
longitude: lon,
|
|
name,
|
|
city,
|
|
address: [housenumber, street].filter(Boolean).join(" "),
|
|
postcode,
|
|
};
|
|
})
|
|
.filter(Boolean);
|
|
|
|
const dedup = new Map();
|
|
for (const store of stores) {
|
|
const key = `${store.latitude.toFixed(5)},${store.longitude.toFixed(5)}`;
|
|
if (!dedup.has(key)) dedup.set(key, store);
|
|
}
|
|
|
|
return Array.from(dedup.values());
|
|
}
|
|
|
|
async function fetchFromOverpass() {
|
|
const endpoints = [
|
|
"https://overpass-api.de/api/interpreter",
|
|
"https://overpass.kumi.systems/api/interpreter",
|
|
"https://overpass.openstreetmap.fr/api/interpreter",
|
|
];
|
|
|
|
for (const endpoint of endpoints) {
|
|
try {
|
|
const response = await fetch(endpoint, {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
|
|
},
|
|
body: new URLSearchParams({ data: query }),
|
|
});
|
|
|
|
if (!response.ok) continue;
|
|
|
|
const payload = await response.json();
|
|
const elements = Array.isArray(payload.elements) ? payload.elements : [];
|
|
const stores = normalizeStores(elements);
|
|
if (stores.length >= 50) return stores;
|
|
} catch {}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function fetchFallbackCsv() {
|
|
const url =
|
|
"https://raw.githubusercontent.com/madmao/castle-compass/master/csv/In%20N%20Out.csv";
|
|
const response = await fetch(url);
|
|
if (!response.ok)
|
|
throw new Error(`Fallback CSV request failed: ${response.status}`);
|
|
|
|
const lines = (await response.text()).split(/\r?\n/).filter(Boolean);
|
|
const stores = lines
|
|
.map((line, index) => {
|
|
const [latRaw, lonRaw] = line.split(",");
|
|
const latitude = Number(latRaw);
|
|
const longitude = Number(lonRaw);
|
|
if (!Number.isFinite(latitude) || !Number.isFinite(longitude))
|
|
return null;
|
|
|
|
const inCaliforniaBounds =
|
|
latitude >= 32 &&
|
|
latitude <= 42.5 &&
|
|
longitude >= -125 &&
|
|
longitude <= -114;
|
|
if (!inCaliforniaBounds) return null;
|
|
|
|
return {
|
|
id: `fallback/${index}`,
|
|
latitude,
|
|
longitude,
|
|
name: "In-N-Out Burger",
|
|
city: "Ville inconnue",
|
|
address: "",
|
|
postcode: "",
|
|
};
|
|
})
|
|
.filter(Boolean);
|
|
|
|
return stores;
|
|
}
|
|
|
|
const stores = (await fetchFromOverpass()) ?? (await fetchFallbackCsv());
|
|
process.stdout.write(JSON.stringify(stores));
|