UNPKG

gopdx

Version:

Command-line Portland, Oregon bus and light rail arrival tracker

341 lines (295 loc) 10.7 kB
#! /usr/bin/env node var http = require('http'); var config = require('./gopdxConfig.js'); var moment = require('moment'); var usage = require('./usage.js'); var chalk = require('chalk'); var prompts = require('@inquirer/prompts'); var fs = require('fs'); var key = require('./key.js'); var Q = require('q'); var inputs = process.argv; var separatorChar = (process.platform == "win32" ? "\\" : "/" ); if(fs.existsSync("favorites.json")){ //legacy file location for 0.1.2 and before var favoritesPath=("favorites.json") } else if (config.favoritesPath == "") { favoritesPath = __dirname + separatorChar + "favorites.json"; } else { favoritesPath = config.favoritesPath; } function processInputs() { var numbersRegEx = new RegExp('[0-9]'); if (!inputs[2]) { usage(); }; if(inputs.includes('-dev')) { config.apiServer = "http://localhost:8000" } if (numbersRegEx.test(inputs[2])) { var deferred = Q.defer(); getArrivals(inputs[2], deferred); deferred.promise.then(function(data){ displayArrivals(data[0], data[1]); }); }; if ((inputs[2] == '-l') || (inputs[2] == '-locate')) { var address = inputs[3]; if((typeof address) != "string"){ console.log("Please enter a street address in quotes after -l to search by address"); process.exit(); } address = address.toLowerCase(); if (address.indexOf("oregon") == -1) { address += ' , oregon'; } getNearbyStops(address, (inputs[4] || null), function (stops) { displayNearbyStops(stops) }); } ; if ((inputs[2] == '-f') || (inputs[2] == '-favorites')) { getArrivalsFromFavorites(); } ; if ((inputs[2] == '-n') || (inputs[2] == '-name') || (inputs[2] == '-keyword') || (inputs[2] == '-k')){ var name = inputs[3]; if((typeof name) != "string"){ console.log("Please enter search terms in quotes separated by spaces to search by keywords"); process.exit(); } name = name.toLowerCase(); getStopsByName(name); } if ((inputs[2] == '-c') || (inputs[2] == '-continuous')){ displayArrivalsContinuously(); } } function getArrivals(stop, deferred) { var arrivals = ''; var waiting = true; http.get(config.apiServer + "/arrivals/" + stop + "?key=" + key(), function (res) { res.on('data', function (chunk) { arrivals += chunk.toString(); }); res.on('end', function () { arrivals = JSON.parse(arrivals); deferred.resolve([stop, arrivals]); }); res.on('error', function (e) { console.error(e); }); }); } function getArrivalsFromFavorites() { var favorites = {}; var deferredArray = []; var promiseArray = []; try { favorites = JSON.parse(fs.readFileSync(favoritesPath, {encoding: 'utf8'})); } catch (err) { console.log("You don't appear to have a favorites file.\n" + "To create one: gopdx -l '123 NW 4th Ave.'"); process.exit(); } if (favorites.favoriteStops.length == 0) { console.log("Your favorites file has no stops.\n" + "To create one: gopdx -l '123 NW 4th Ave.'"); process.exit(); } favorites.favoriteStops.forEach(function (stop, index) { deferredArray[index] = Q.defer(); promiseArray[index] = deferredArray[index].promise; getArrivals(stop, deferredArray[index]); }); Q.all(promiseArray).then(function(){ promiseArray.forEach(function(item){ displayArrivals(item[0], item[1]); }); }); } function displayArrivals(stop, arrivalData) { var arrivalsFound = 0; console.log(chalk.cyan('Stop number: ' + chalk.bold(stop)) + " " + chalk.green(arrivalData.resultSet.location[0].desc)); if (arrivalData.resultSet.arrival) { arrivalData.resultSet.arrival.forEach(function (arrival) { ; if (arrival.status == "scheduled") { arrivalsFound++; var arrivalTime = moment(arrival.scheduled); if (arrivalTime > moment()) { console.log(chalk.bold(arrival.shortSign) + " " + arrivalTime.fromNow() + " at " + arrivalTime.format('h:mm a') + chalk.yellow(" [scheduled]")); } } else { arrivalTime = moment(arrival.estimated); if (arrivalTime > moment()) { arrivalsFound++; console.log(chalk.bold(arrival.shortSign) + " " + arrivalTime.fromNow() + " at " + arrivalTime.format('h:mm a') + chalk.green(" [actual]")); } } }) if (arrivalsFound == 0) { console.log("Sorry, no arrivals currently found for that stop."); } } else { console.log("Sorry, no arrivals currently found for that stop."); } } function getNearbyStops(address, distance, callback) { var nearByStops = ''; var distanceQueryString = ''; if (distance) { var distanceQueryString = '?distance=' + distance; } getCoordinates(address, function (locationData) { var lat = locationData[0].geometry.lat; var lng = locationData[0].geometry.lng; http.get(config.apiServer + "/stops?lat=" + lat + "&lng=" + lng + "&key=" + key(), function (res) { var stops = ''; res.on('data', function (chunk) { stops += chunk.toString(); }); res.on('end', function () { stops = JSON.parse(stops); displayNearbyStops(stops); }); res.on('error', function (e) { console.error(e); }); }); }) } function getCoordinates(address, callback) { http.get(config.apiServer + "/coordinates/" + encodeURI(address) + "?key=" + key(), function (res) { var mqData = ''; res.on('data', function (chunk) { mqData += chunk.toString(); }); res.on('end', function () { mqData = JSON.parse(mqData); var oregonLocations = parseOregonLocations(mqData); if (oregonLocations.length == 0){ console.log("No Oregon address found, perhaps try a -keyword search?"); process.exit(); } if (oregonLocations.length > 1){ console.log("More than one possible location found, add more address info or perhaps try a -keyword search?"); process.exit(); } callback(oregonLocations); }); res.on('error', function (e) { console.log(e); }); }); } async function displayNearbyStops(stops) { if (stops.resultSet.location) { var stopsArray = {favoriteStops: []}; stops.resultSet.location.forEach( function (stop) { var lines = []; if(stop.route){ stop.route.forEach(function (route) { lines.push(" " + route.desc + " " + route.dir[0].desc); }); } //console.log(stop); stopsArray.favoriteStops.push({name: stop.desc + " ID: " + stop.locid + "\n Lines:\n" + lines.join('\n'), value: stop.locid}); } ) const answer = await prompts.checkbox({ message: 'Please select any stops to save to your favorites:', choices: stopsArray.favoriteStops }); saveStopsToFavorites(answer); } else { console.log("We couldn't find any stops for that area"); } } function saveStopsToFavorites(selectedStops) { var favorites = {favoriteStops: []}; try { favorites = JSON.parse(fs.readFileSync(favoritesPath, {encoding: 'utf8'})); } catch (err) { //console.log(err); } favorites.favoriteStops = [...new Set([...favorites.favoriteStops, ...selectedStops])]; try { fs.writeFileSync(favoritesPath, JSON.stringify(favorites), {encoding: 'utf8'}); console.log("Stops saved to your favorites file. \n" + "To check arrivals from favorites use gopdx -f"); } catch (err) { console.log("We couldn't write to your favorites file!\nMake sure NodeJS has write permissions for the directory " + favoritesPath + " or set your own directory path (including file name) in the gopdxConfig.js file, " + "like /tmp/favorites.json or similar"); } } function parseOregonLocations(locationData) { var oregonLocations = []; if(locationData.components.state == "Oregon"){ oregonLocations.push(locationData); } return oregonLocations; } function getStopsByName(name){ var stops = ''; var choiceArray = []; http.get((config.apiServer + "/namesearch?key=" + key() + "&searchterms=" + encodeURI(name)), function(res){ res.on('data', function(chunk){ stops += chunk.toString(); }); res.on('end',async function(){ stops = JSON.parse(stops); if(stops.error){ console.log(stops.error); process.exit(); } stops.forEach(function(stop){ if(typeof (stop.stop_id) == "number"){ choiceArray.push({ name:stop.stop_name + " - ID: "+ stop.stop_id +" - Direction: " + stop.direction, value:stop.stop_code}); } }); const answer = await prompts.checkbox({ message: 'Please select any stops to save to your favorites:', choices: choiceArray }); saveStopsToFavorites(answer); }); res.on('error',function(err){ console.log(err); }); }) } function displayArrivalsContinuously(){ process.stdout.write('\x1B[2J'); process.stdout.write('\x1B[0;0H'); getArrivalsFromFavorites(); var windowResized = true; process.stdin.resume(); process.on('SIGWINCH', function() { windowResized = true; //getArrivalsFromFavorites(); }); setInterval( function(){ if(windowResized){ process.stdout.write('\x1B[2J'); process.stdout.write('\x1B[0;0H'); windowResized = false; } getArrivalsFromFavorites(); process.stdout.write('\x1B[0;0H'); }, 10000) } processInputs();