Last active
December 8, 2021 01:08
-
-
Save druv5319/7b3c4d2626c0e9055e1c51f0d6852081 to your computer and use it in GitHub Desktop.
Sneaker price tracker using SendGrid and Node.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require('dotenv').config() | |
const SneaksAPI = require('sneaks-api'); | |
const fs = require("fs"); | |
const schedule = require('node-schedule'); | |
const sneaks = new SneaksAPI(); | |
const sgMail = require('@sendgrid/mail'); | |
sgMail.setApiKey(process.env.SENDGRID_API_KEY); | |
const jsonString = fs.readFileSync("./subscribers.json"); | |
const subscribers = JSON.parse(jsonString); | |
(async function main() { | |
const sneakerMap = await getSneakerMap(subscribers); | |
for await (const subscriber of subscribers) { | |
if (sneakerMap[subscriber.styleID].price < subscriber.lastResellPrice - 10) { | |
notifySubscriber(sneakerMap[subscriber.styleID], subscriber.email); | |
subscriber.lastResellPrice = sneakerMap[subscriber.styleID].price; | |
} | |
} | |
fs.writeFileSync("./subscribers.json", JSON.stringify(subscribers)); | |
})() | |
async function getSneakerMap(subscribers) { | |
var sneakerMap = new Object(); | |
for (const subscriber of subscribers) { | |
if (sneakerMap[subscriber.styleID]) continue; | |
const sneaker = await sneaksApiFunctionWrapper(subscriber.styleID); | |
sneakerMap[subscriber.styleID] = sneaker; | |
} | |
return sneakerMap; | |
} | |
function notifySubscriber(sneaker, email) { | |
const msg = { | |
to: RECIPIENT_EMAIL, // Change to your recipient | |
from: SENDER_EMAIL, // Change to your verified sender | |
subject: `Price Drop - ${sneaker.name}`, | |
html: createEmailInHTML(sneaker), | |
} | |
sgMail.send(msg) | |
.then((response) => { | |
console.log(response[0].statusCode) | |
console.log(response[0].headers) | |
}) | |
.catch((error) => { | |
console.error(error) | |
}) | |
} | |
function sneaksApiFunctionWrapper(styleID) { | |
return new Promise((resolve, reject) => { | |
sneaks.getProductPrices(styleID, function (err, product) { | |
const lowestResellSite = Object.keys(product.lowestResellPrice).reduce((a, b) => product.lowestResellPrice[a] > product.lowestResellPrice[b] ? a : b); | |
const sneaker = { | |
name: product.shoeName, | |
image: product.thumbnail, | |
site: lowestResellSite, | |
price: product.lowestResellPrice[lowestResellSite], | |
url: product.resellLinks[lowestResellSite], | |
styleID: product.styleID | |
}; | |
resolve(sneaker); | |
}, (errorResponse) => { | |
reject(errorResponse); | |
}); | |
}); | |
} | |
function createEmailInHTML(sneaker) { | |
return ` | |
<h2> | |
<img style="font-size:14px;display:block;margin-left:auto;margin-right:auto;width:200px; padding-bottom:15px" src="https://raw.githubusercontent.com/druv5319/Sneaks-API/master/Screenshots/Sneaks_Logo.png"/> | |
</h2> | |
<div style=" margin-left: auto; margin-right: auto;box-sizing:border-box;width:45%; margin-bottom:30px;background:#fdfdfd;border:1px solid #f0f0f0"> | |
<h2 style="text-align: center; color: black; font-family: 'avenir';">Price Drop - ${sneaker.name}</h2> | |
<p> | |
<img style="display: block; margin-left: auto; margin-right: auto;" src=${sneaker.image} alt="" width="auto" height="250" /> | |
</p> | |
<h2 style="text-align: center; color: black; font-family: 'avenir';">$${sneaker.price}</h2> | |
<p> </p> | |
<p style="font-size: 1.5em; color: black; font-family: avenir; text-align: center;">${sneaker.name} has dropped to | |
<strong>$${sneaker.price}</strong> on <strong>${sneaker.site}</strong></p> | |
<p style="text-align: center;"> | |
<a href="${sneaker.url}" style="box-sizing:border-box;border-color:#348eda;font-weight:400;text-decoration:none;display:inline-block;margin:0;color:#ffffff;background-color:#348eda;border:solid 1px #348eda;border-radius:2px;font-size:14px;padding:12px 45px; font-weight: 600;">Buy now on ${sneaker.site}</a> | |
</p> | |
</div>`; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment