Files
to-hen/osm-restaurants/osm-restaurants.js

107 lines
2.8 KiB
JavaScript
Raw Normal View History

2022-10-12 01:14:53 +02:00
#!/usr/bin/env node
const crypto = require("crypto");
const fs = require("fs");
const os = require("os");
const path = require("path");
const axios = require("axios");
const openingHours = require("opening_hours");
const yargs = require("yargs");
const CACHE_AGE = 12 * 60 * 60 * 1000;
const md5 = (text) => crypto.createHash("md5").update(text).digest("hex");
const getCachePath = (query) => {
const cacheDirectory =
process.env.CACHE_DIR ||
path.join(os.homedir(), ".cache", "osm-restaurants");
if (!fs.existsSync(cacheDirectory)) fs.mkdirSync(cacheDirectory);
return path.join(cacheDirectory, md5(query) + ".json");
};
const randomElement = (array) =>
array[Math.floor(array.length * Math.random())];
const argv = yargs
.option("checkOpen", {
alias: "o",
default: true,
type: "boolean",
description: "Only show restaurants that are open",
})
.option("radius", {
alias: "r",
description: "Radius around the location (metres)",
type: "number",
default: 500,
})
.option("center", {
alias: "c",
description: "The OSM ID to search around",
type: "number",
demandOption: true,
})
.option("endpoint", {
description: "The Overpass API endpoint",
type: "string",
default: "http://overpass-api.de/api/interpreter",
})
.option("country", {
description: "The country you are in (two letter code)",
type: "string",
default: "de",
})
.help()
.alias("help", "h").argv;
const overpassQuery = `
[out:json];
node(id:${argv.center})->.center;
(
node(around.center:'${argv.radius}')[amenity=fast_food];
node(around.center:'${argv.radius}')[amenity=restaurant];
);
out;
`;
const restaurantOpen = (restaurant) =>
"opening_hours" in restaurant.tags
? new openingHours(restaurant.tags.opening_hours, {
lat: restaurant.lat,
lon: restaurant.lon,
address: {
country_code:
"addr:country" in restaurant.tags
? restaurant.tags["addr:country"].toLowerCase()
: argv.country,
},
}).getState()
: true;
const withRestaurants = (callback) => {
const cachePath = getCachePath(overpassQuery);
if (
fs.existsSync(cachePath) &&
new Date() - fs.statSync(cachePath).mtime > CACHE_AGE
)
return JSON.parse(fs.readFileSync(cachePath));
else
return axios
.post(argv.endpoint, overpassQuery)
.then((response) => {
const restaurants = response.data.elements;
fs.writeFileSync(cachePath, JSON.stringify(restaurants));
callback(restaurants);
})
.catch(console.error);
};
withRestaurants((restaurants) => {
const randomOpenRestaurant = randomElement(
argv.checkOpen ? restaurants.filter(restaurantOpen) : restaurants
);
console.log(JSON.stringify(randomOpenRestaurant));
});