Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,6 @@ dist

# TernJS port file
.tern-port

cache/
history/
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,5 @@ This requires a valid Amadeus API set of keys.
After you have your API keys, place them in the `.env` file (see the `.env.example` for the keys)

## How to run
Execute `npm run dev` and go to localhost:3000 in your browser

In the `origins.txt` file place the airports codes for the origin airports (list the same code more than once if you have multiple people departing from the same airport).

After you installed the dependencies (`npm install`) you can do a search with

`npm run main ./origins.txt "DESTINATION" "DEPARTURE-DATE" "RETURN-DATE"`

example:
`npm run main ./origins.txt "NYC" "2023-04-01" "2023-04-10"`
2 changes: 2 additions & 0 deletions destinations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
JFK
LAX
96 changes: 70 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,57 @@ const fs = require("fs");
const readline = require("readline");
const Amadeus = require("amadeus");
const dotenv = require("dotenv");
const { parse } = require("path");


dotenv.config();

const ORIGINS_FILE = process.argv[2]; // Get path to file containing origin airport codes from command-line arguments
const DESTINATION = process.argv[3]; // Get destination airport code from command-line arguments
const DESTINATIONS_FILE = process.argv[3]; // Get destination airport code from command-line arguments
const DEPARTURE_DATE = process.argv[4]; // Get departure date from command-line arguments
const RETURN_DATE = process.argv[5]; // Get return date from command-line arguments

const OUTPUT_FILE = process.argv[6]; // Get location for output csv
const amadeus = new Amadeus({
clientId: process.env.AMADEUS_API_KEY,
clientSecret: process.env.AMADEUS_API_SECRET,
});

async function getAirfarePrice(origin, pricesCache) {
if (pricesCache[origin] !== undefined) {
async function getAirfarePrice(origin, destination, pricesCache) {
const cacheKey = `${origin}-${destination}`;
if (pricesCache[cacheKey] !== undefined) {
console.log(
`Using cached price from ${origin} to ${DESTINATION} on ${DEPARTURE_DATE} - ${RETURN_DATE}: $${pricesCache[origin]}`
`Using cached price from ${origin} to ${destination} on ${DEPARTURE_DATE} - ${RETURN_DATE}: $${pricesCache[cacheKey]}`
);
return pricesCache[origin];
return pricesCache[cacheKey];
}
console.log(
`Checking prices from ${origin} to ${destination}`
);
if(origin == destination){
return 0; //if origin and location are the same we can skip the check and return $0
}
try {
const response = await amadeus.shopping.flightOffersSearch.get({
originLocationCode: origin,
destinationLocationCode: DESTINATION,
destinationLocationCode: destination,
departureDate: DEPARTURE_DATE,
returnDate: RETURN_DATE,
adults: 1,
currencyCode: "USD",
max: 3,
max: 2,
});
if (response?.data && response.data.length > 0) {
const price = response.data[0].price.total;
const numFlights = response.data[0].itineraries[0].segments.length;
const flighttime = response.data[0].itineraries[0].duration;
console.log(
`Airfare price from ${origin} to ${DESTINATION} on ${DEPARTURE_DATE} - ${RETURN_DATE}: $${price}`
`Airfare price from ${origin} to ${destination} on ${DEPARTURE_DATE} - ${RETURN_DATE}: $${price} with ${numFlights} Flights. Travel time: ${flighttime}`
);
pricesCache[origin] = price - 0;
return pricesCache[origin];
pricesCache[cacheKey] = price;
return price;
}
console.error(
`[NOT-FOUND] Airfare price from ${origin} to ${DESTINATION} on ${DEPARTURE_DATE} - ${RETURN_DATE} could not be found`
`[NOT-FOUND] Airfare price from ${origin} to ${destination} on ${DEPARTURE_DATE} - ${RETURN_DATE} could not be found`
);
return 0;
} catch (error) {
Expand All @@ -51,22 +62,55 @@ async function getAirfarePrice(origin, pricesCache) {
}

async function main() {
let totalPrice = 0;

const destinations = fs.readFileSync(DESTINATIONS_FILE, "utf8").split("\n").map(d => d.trim()).filter(d => d);
const pricesCache = {};
const rl = readline.createInterface({
input: fs.createReadStream(ORIGINS_FILE),
crlfDelay: Infinity,
});

for await (const origin of rl) {
const price = await getAirfarePrice(origin.trim(), pricesCache);
totalPrice += price;
const results = {};

for (const destination of destinations) {
results[destination] = {};
}

console.log(
`Total airfare price from all origins in ${ORIGINS_FILE} to ${DESTINATION} on ${DEPARTURE_DATE} - ${RETURN_DATE}: $${totalPrice}`
);
const origins = fs.readFileSync(ORIGINS_FILE, "utf8").split("\n").map(d => d.trim()).filter(d => d);


for await (const destination of destinations) {
let totalPrice = 0;
let corigins = 0;
let averagePrice = 0;
for (const origin of origins) {
corigins++;
const price = await getAirfarePrice(origin, destination, pricesCache);
totalPrice += parseFloat(price);
averagePrice = totalPrice / corigins;
results[destination][origin] = price;
}
console.log(`Current average is $${averagePrice} for ${corigins} flights to ${destination}`);
}

// Prepare CSV output
let csv = 'Origin/Destination,' + destinations.join(',') + '\n';
const totals = new Array(destinations.length).fill(0);
let totalSum = 0;

for (const [origin, prices] of Object.entries(results[destinations[0]])) {
let row = `${origin},`;
let sum = 0;
let count = 0;

destinations.forEach((destination, index) => {
const price = results[destination][origin] || 0;
row += `${price},`;
totals[index] += price;
if (price > 0) count++;
});

csv += `${row}\n`;
}


// Write CSV to file
fs.writeFileSync(OUTPUT_FILE, csv);
console.log(`Airfare prices have been written to ${OUTPUT_FILE}`);
}

main();
main();
17 changes: 17 additions & 0 deletions nodemon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"verbose": true,
"ignore": [
"cache/*",
"*.test.js",
"*.json",
"public/*"
],
"events": {
"crash": "echo 'Application crashed - waiting for changes before restarting...'"
},
"delay": "1500",
"restartable": "rs",
"env": {
"NODE_ENV": "development"
}
}
Loading