generated from me/template-mit
Move Node.js prototype to a separate cli folder. Works great!
This commit is contained in:
1 parent
bd02d4611a
commit
b3d3573fae
5 files changed
No files matched your search
@@ -0,0 +1,34 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
|
||||
# Build output
|
||||
dist/
|
||||
build/
|
||||
out/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
!.env.example
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Caches
|
||||
.npm
|
||||
.eslintcache
|
||||
.cache/
|
||||
coverage/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
#!/usr/bin/env bash
|
||||
# 20260912 - Hyperling
|
||||
# "Install" script to get this program runnable from anywhere on the system.
|
||||
|
||||
## Variables ##
|
||||
|
||||
DIR="$(cd "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
|
||||
PROG="$(basename -- "${BASH_SOURCE[0]}")"
|
||||
LOCAL=~/bin
|
||||
GLOBAL=/usr/local/bin
|
||||
GLOBAL_SRC=/usr/local/src
|
||||
|
||||
name_local="prototype.js"
|
||||
name_short="nomad"
|
||||
name_long="nomadic-weather"
|
||||
name_abs="weather-list"
|
||||
|
||||
## Functions ##
|
||||
|
||||
function usage {
|
||||
cat <<- EOF
|
||||
$PROG [-h] [-g] [a|l|s] [-r]
|
||||
|
||||
Install $name_local to the system. Can be local, global, or removed.
|
||||
|
||||
Parameters)
|
||||
h) Display this message.
|
||||
g) Install globally ($GLOBAL), otherwise local ($LOCAL).
|
||||
a) Abstract name, unrelated to being nomadic. ($name_abs)
|
||||
l) Long name, the full name of the project. ($name_long)
|
||||
s) Short name, the full name of the project. ($name_short)
|
||||
r) Remove / uninstall the project according to the above flags.
|
||||
|
||||
Examples)
|
||||
- Install to the local user with the abstract name.
|
||||
$PROG
|
||||
- Install to all users with all names.
|
||||
$PROG -alsg
|
||||
- Remove all instances.
|
||||
$PROG -alsr && $PROG -alsrg
|
||||
|
||||
Happy weather watching! :)
|
||||
|
||||
~ Hyperling
|
||||
EOF
|
||||
exit $1
|
||||
}
|
||||
|
||||
## Parameters ##
|
||||
|
||||
while getopts ":gslarh" arg; do
|
||||
case $arg in
|
||||
g) global="Y" ;;
|
||||
s) short="Y" ;;
|
||||
l) long="Y" ;;
|
||||
a) abstract="Y" ;;
|
||||
r) remove="Y" ;;
|
||||
h) usage ;;
|
||||
*) echo "ERROR: Parameter $OPTARG was not recognized." && usage 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
## Processing ##
|
||||
|
||||
name=""
|
||||
if [[ "$short" == "Y" ]]; then
|
||||
name="$name $name_short"
|
||||
fi
|
||||
if [[ "$long" == "Y" ]]; then
|
||||
name="$name $name_long"
|
||||
fi
|
||||
if [[ "$abstract" == "Y" || ( -z "$short" && -z "$long" ) ]]; then
|
||||
name="$name $name_abs"
|
||||
fi
|
||||
|
||||
cmd=""
|
||||
dir="$LOCAL"
|
||||
src="$DIR"
|
||||
if [[ "$global" == "Y" ]]; then
|
||||
dir="$GLOBAL"
|
||||
cmd="sudo"
|
||||
echo "Requesting sudo privileges... "
|
||||
sudo echo "Success!"
|
||||
mkdir -pv /usr/local/src
|
||||
sudo cp -Rv "$DIR" $GLOBAL_SRC/
|
||||
src="$GLOBAL_SRC/`basename "$DIR"`"
|
||||
fi
|
||||
|
||||
if [[ -z "$remove" ]]; then
|
||||
cmd="$cmd ln -svf $src/$name_local"
|
||||
else
|
||||
cmd="$cmd rm -v"
|
||||
fi
|
||||
|
||||
## Main ##
|
||||
|
||||
# Untested
|
||||
#if [[ "$global" == "Y" && "$remove" == "Y" ]]; then
|
||||
# sudo rm -rfv "$src"
|
||||
#fi
|
||||
|
||||
for prog in $name; do
|
||||
mkdir -pv "$dir"
|
||||
$cmd "$dir/$prog"
|
||||
done
|
||||
|
||||
## Finish ##
|
||||
|
||||
echo "Done!"
|
||||
exit 0
|
||||
Generated
+203
@@ -0,0 +1,203 @@
|
||||
{
|
||||
"name": "nomadic-weather",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"yargs": "^18.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz",
|
||||
"integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
||||
"integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^7.2.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
|
||||
"integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "8.2.2",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz",
|
||||
"integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.5.0",
|
||||
"strip-ansi": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
|
||||
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
|
||||
"integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "18.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz",
|
||||
"integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^9.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"string-width": "^8.2.1",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^22.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "22.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
|
||||
"integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"yargs": "^18.1.0"
|
||||
}
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
#!/usr/bin/env node
|
||||
"use strict";
|
||||
// 2026-09-12 - Hyperling
|
||||
/* Prototype mostly generated by Ask Brave from prompt:
|
||||
* node.js script which has 8 location variables including name, lat, lon, and elevation.
|
||||
* loops over the locations sending them to open-meteo requesting temperature min and max for 7 days, no hourly.
|
||||
* uses units for USA such as fahrenheit, inches, mph.
|
||||
* prints the location name and elevation with the average high and low for the week.
|
||||
* */
|
||||
// Maybe AI is actually getting better than I thought. ;D
|
||||
|
||||
/* AI Updates:
|
||||
* - highlight highs between 60 and 75, highlight lows between 40 and 55
|
||||
* - order locations by elevation ascending
|
||||
* */
|
||||
|
||||
/* User Updates
|
||||
* - fix spacing in table
|
||||
* - move temps to be right aligned
|
||||
* - send elevation to API
|
||||
* - new highlighting function with many other colors
|
||||
* - added apparent (feels like)
|
||||
* - added args, basically took over the program without any incremental commits
|
||||
* */
|
||||
|
||||
const yargs = require('yargs/yargs');
|
||||
const { hideBin } = require('yargs/helpers');
|
||||
|
||||
const version = '0.0.1';
|
||||
|
||||
const days_fore_max = 16;
|
||||
const days_fore_default = 12;
|
||||
const days_past_default = 2;
|
||||
|
||||
const ft_to_m = 0.3048;
|
||||
|
||||
const argv = yargs(hideBin(process.argv))
|
||||
.option('days_fore', {
|
||||
alias: 'f',
|
||||
describe: 'Set forecast days, such as "-f 10". Maximum of 16.',
|
||||
type: 'number',
|
||||
requiresArg: true,
|
||||
})
|
||||
.option('days_past', {
|
||||
alias: 'p',
|
||||
describe: 'Set past days, such as "-p 3"',
|
||||
type: 'number',
|
||||
requiresArg: true,
|
||||
})
|
||||
.option('calc_elevation', {
|
||||
alias: 'e',
|
||||
describe: 'Set to calculate elevation at lat/long.',
|
||||
type: 'boolean',
|
||||
})
|
||||
.check((argv) => {
|
||||
if (argv.f !== undefined && (isNaN(argv.f) || argv.f < 0)) {
|
||||
throw new Error('Forecast days must be a non-negative number');
|
||||
}
|
||||
if (argv.p !== undefined && (isNaN(argv.p) || argv.p < 0)) {
|
||||
throw new Error('Past days must be a non-negative number');
|
||||
}
|
||||
return true;
|
||||
})
|
||||
//.demandOption(['timeout', 'debug']) // Optional: require these arguments
|
||||
.strict()
|
||||
.help()
|
||||
.version(version)
|
||||
.argv
|
||||
;
|
||||
|
||||
function max (value, upper) {
|
||||
return (value > upper) ? upper : value;
|
||||
}
|
||||
const days_fore = max(argv.hasOwnProperty("days_fore") ? argv.days_fore : days_fore_default, days_fore_max);
|
||||
const days_past = argv.hasOwnProperty("days_past") ? argv.days_past : days_past_default;
|
||||
const calc_elevation = argv.calc_elevation ? true : false;
|
||||
|
||||
const days = days_fore + days_past;
|
||||
|
||||
console.log(`Averaging for ${days} days: ${days_fore} forecasted, ${days_past} past.`);
|
||||
if (calc_elevation) console.log("Calculating elevation rather than using provided values.");
|
||||
else console.log("Using user-provided elevations when they exist.");
|
||||
|
||||
const locations = [
|
||||
//{ name: "Flagstaff, AZ", lat: 35.1983, lon: -111.6513, elevation: 6903 },
|
||||
//{ name: "Flagstaff: NG", lat: 35.1983, lon: -111.6513, elevation: 6931 },
|
||||
{ name: "Flagstaff: ++", lat: 35.1983, lon: -111.6513, elevation: 8200 },
|
||||
//{ name: "Tucson, AZ", lat: 32.2226, lon: -110.9747, elevation: 2490 },
|
||||
//{ name: "Tucson: NG", lat: 32.2226, lon: -110.9747, elevation: 2483 },
|
||||
//{ name: "Tucson: GV", lat: 32.2226, lon: -110.9747, elevation: 2371 },
|
||||
{ name: "Tucson: ++", lat: 32.2226, lon: -110.9747, elevation: 2150 },
|
||||
//{ name: "Prescott, AZ", lat: 34.5400, lon: -112.4685, elevation: 5374 },
|
||||
//{ name: "Prescott: NG", lat: 34.5400, lon: -112.4685, elevation: 5496 },
|
||||
{ name: "Prescott: ++", lat: 34.5400, lon: -112.4685, elevation: 6400 },
|
||||
//{ name: "Frisco, CO", lat: 39.5744, lon: -106.0975, elevation: 9075 },
|
||||
//{ name: "Frisco: NG", lat: 39.5744, lon: -106.0975, elevation: 9067 },
|
||||
{ name: "Frisco: ++", lat: 39.5744, lon: -106.0975, elevation: 10200 },
|
||||
//{ name: "Greer, AZ", lat: 34.0100, lon: -109.4587, elevation: 8356 },
|
||||
{ name: "Greer: ++", lat: 34.0100, lon: -109.4587, elevation: 9000 },
|
||||
//{ name: "Sedona, AZ", lat: 34.8697, lon: -111.7610, elevation: 4350 },
|
||||
{ name: "Sedona: ++", lat: 34.8697, lon: -111.7610, elevation: 4500 },
|
||||
{ name: "Cottonwood: ++", lat: 34.7392, lon: -112.0099, elevation: 3600 },
|
||||
{ name: "Cherry: ++", lat: 34.5781, lon: -112.0677, elevation: 5300 },
|
||||
//{ name: "Sedona: NG", lat: 34.8697, lon: -111.7610, elevation: 4420 },
|
||||
//{ name: "Ehrenberg, AZ", lat: 33.9897, lon: -114.3550, elevation: 333 },
|
||||
{ name: "Ehrenberg: ++", lat: 33.9897, lon: -114.3550, elevation: 300 },
|
||||
{ name: "Quartzsite: ++", lat: 33.6763, lon: -114.2104, elevation: 900 },
|
||||
];
|
||||
locations.sort((a, b) => a.elevation - b.elevation);
|
||||
|
||||
const RED = "\x1b[31m";
|
||||
const GRN = "\x1b[32m";
|
||||
const YLW = "\x1b[33m";
|
||||
const BLU = "\x1b[34m";
|
||||
const MGN = "\x1b[35m";
|
||||
const CYN = "\x1b[36m";
|
||||
const WHT = "\x1b[37m";
|
||||
const RESET = "\x1b[0m";
|
||||
|
||||
function highlight(value, min, max) {
|
||||
const n = parseFloat(value);
|
||||
return (n >= min && n <= max) ? `${GRN}${value}${RESET}` : value;
|
||||
}
|
||||
|
||||
const pref_high_upper = 75;
|
||||
const pref_high_lower = 60;
|
||||
const pref_low_upper = 55;
|
||||
const pref_low_lower = 40;
|
||||
|
||||
const tolerance_light = 10;
|
||||
const tolerance_heavy = 20;
|
||||
|
||||
function check (value, min, max) {
|
||||
const n = parseFloat(value);
|
||||
|
||||
var CLR = "";
|
||||
|
||||
if (n >= max + tolerance_heavy)
|
||||
CLR = MGN;
|
||||
else if (n >= max + tolerance_light)
|
||||
CLR = RED;
|
||||
else if (n >= max)
|
||||
CLR = YLW;
|
||||
else if (n <= max && n >= min)
|
||||
CLR = GRN;
|
||||
else if (n <= min - tolerance_heavy)
|
||||
CLR = WHT
|
||||
else if (n <= min - tolerance_light)
|
||||
CLR = CYN
|
||||
else if (n <= min)
|
||||
CLR = BLU;
|
||||
else
|
||||
CLR = RESET;
|
||||
|
||||
return `${CLR}${value}${RESET}`;
|
||||
//return (n >= min && n <= max) ? `${GRN}${value}${RESET}` : value;
|
||||
}
|
||||
|
||||
function pad(str, width) {
|
||||
const visible = str.replace(/\x1b\[\d+m/g, '').length;
|
||||
return ' '.repeat(Math.max(0, width - visible)) + str;
|
||||
}
|
||||
|
||||
async function getForecast(loc) {
|
||||
const url = new URL("https://api.open-meteo.com/v1/forecast");
|
||||
url.searchParams.set("latitude", loc.lat);
|
||||
url.searchParams.set("longitude", loc.lon);
|
||||
if (!calc_elevation && loc.elevation) url.searchParams.set("elevation", loc.elevation * ft_to_m);
|
||||
url.searchParams.set("daily", "temperature_2m_max,temperature_2m_min,apparent_temperature_max,apparent_temperature_min");
|
||||
url.searchParams.set("temperature_unit", "fahrenheit");
|
||||
url.searchParams.set("precipitation_unit", "inch");
|
||||
url.searchParams.set("wind_speed_unit", "mph");
|
||||
url.searchParams.set("timezone", "auto");
|
||||
url.searchParams.set("forecast_days", days_fore);
|
||||
url.searchParams.set("past_days", days_past);
|
||||
|
||||
const res = await fetch(url);
|
||||
const data = await res.json();
|
||||
|
||||
const highs = data.daily.temperature_2m_max;
|
||||
const lows = data.daily.temperature_2m_min;
|
||||
|
||||
const avgHigh = (highs.reduce((a, b) => a + b, 0) / highs.length).toFixed(1);
|
||||
const avgLow = (lows.reduce((a, b) => a + b, 0) / lows.length).toFixed(1);
|
||||
|
||||
const highs2 = data.daily.apparent_temperature_max;
|
||||
const lows2 = data.daily.apparent_temperature_min;
|
||||
|
||||
const avgHigh2 = (highs2.reduce((a, b) => a + b, 0) / highs2.length).toFixed(1);
|
||||
const avgLow2 = (lows2.reduce((a, b) => a + b, 0) / lows2.length).toFixed(1);
|
||||
|
||||
const elev = (!calc_elevation && loc.elevation) ? loc.elevation : (data.elevation / ft_to_m).toFixed(0);
|
||||
|
||||
return { name: loc.name, elevation: elev, avgHigh, avgLow, avgHigh2, avgLow2 };
|
||||
}
|
||||
|
||||
(async () => {
|
||||
console.log("Location | Elev (ft) | High (°F) | Low (°F) | FeelH (°F) | FeelL (°F)");
|
||||
console.log("----------------------+-----------+-----------+----------+------------+------------");
|
||||
|
||||
for (const loc of locations) {
|
||||
try {
|
||||
const r = await getForecast(loc);
|
||||
const hi = check(r.avgHigh, pref_high_lower, pref_high_upper);
|
||||
const lo = check(r.avgLow, pref_low_lower, pref_low_upper);
|
||||
const hi2 = check(r.avgHigh2, pref_high_lower, pref_high_upper);
|
||||
const lo2 = check(r.avgLow2, pref_low_lower, pref_low_upper);
|
||||
console.log(
|
||||
`${pad(r.name, 21)} | ${pad(String(r.elevation), 9)} | ${pad(hi, 9)} | ${pad(lo, 8)} | ${pad(hi2, 10)} | ${pad(lo2, 10)}`
|
||||
);
|
||||
} catch (e) {
|
||||
console.log(`${loc.name}: error – ${e.message}`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Reference in new issue
Block a user