Skip to content

Instantly share code, notes, and snippets.

@Calvein
Created July 18, 2012 19:19
Show Gist options
  • Save Calvein/3138232 to your computer and use it in GitHub Desktop.
Save Calvein/3138232 to your computer and use it in GitHub Desktop.
Node app to receive emails of the Steam sales
// $ npm install node-phantom nodemailer moment lodash
// Modules definitions
var phantom = require('node-phantom')
, nodemailer = require("nodemailer")
, moment = require('moment')
, _ = require('lodash')
// Email stuff
var smtpTransport = nodemailer.createTransport("SMTP",{
service: "Gmail"
, auth: {
user: "[email protected]"
, pass: "password"
}
})
// The HTML template for the email
var template = function(game) {
return '<tr><td>'+
'<a href="' + game.link + '"><b>' + game.name + '</b></a>'+
'<td>'+
'<b>' + game.price + '</b> <i>' + game.discount + '</i> fin <b>' + moment(game.timeLeft).fromNow() + '</b>'
}
// Moment stuff
var now = moment()
// Today at 20:00
, endSaleDay = moment([2012, 6, now.date(), 20])
// If today at 20:00 is passed, then tomorrow
if (now.unix() > endSaleDay.unix()) {
endSaleDay = moment([2012, 6, now.date() + 1, 20])
}
phantom.create(function(err, ph) {
ph.createPage(function(err, page) {
var loop = function() {
console.log('Loading page...')
page.open('http://store.steampowered.com/', function(err, status) {
console.log('Page opened.')
page.evaluate(function() {
var games = []
/**
* Return the seconds in a "Steam-time-expression" (hh:mm:ss)
* It has to be redeclare each time because page.evaluate() is pretty much a big eval
*
* @param {string} time the time as hh:mm:ss
* @return {int} the seconds
*/
, timeToSecond = function(time) {
if (time) {
var seconds = 0
time.split(':').reverse().forEach(function(t, i) {
seconds += Math.pow(60, i) * t * 1000
})
return ~~seconds
}
}
/**
* Get the type of saled item
*
* @param {element} el The element to test
* @return {string} The type (top, flash, daily)
*/
, getType = function(el) {
var type = null;
if (el.id) {
type = 'top'
} else if (el.querySelector('.timeleft')) {
type = 'flash'
} else {
type = 'daily'
}
return type
}
, timesLeft = []
, game
, type
, timeLeft
, discount
, link
// Get the top voted one and the flashes
;[].forEach.call(document.querySelectorAll('#ss_topvoted, #ss_flash > .app, #ss_daily > .app'), function(el) {
type = getType(el)
link = el.querySelector('a')
game = link.title
fullTime = // The time isn't the same
type === 'top' ? document.querySelector('#topvoted_timer') :
el.querySelector('.timer')
timeLeft = timeToSecond(fullTime ? fullTime.innerText : null)
timeLeft && timesLeft.push(timeLeft)
discount = el.querySelector('.discount')
games.push({
name : game
, type : type
, price : discount.querySelector('span:not(.was)').innerText.trim()
, discount: discount.firstChild.textContent.trim()
, link : link.href
, timeLeft: timeLeft
})
})
return {
games : games
, timesLeft : timesLeft
}
}, function(err, data) {
// The next refresh will occur at the minimum timeLeft + 5 seconds
data.timesLeft.push(endSaleDay / 1000)
var nextRefresh = Math.min.apply(null, data.timesLeft) + 5000
console.log('Next refresh in ' + nextRefresh + 's')
// Email sending
var html = '<h2>Jeux en promos</h2><table>'
_.each(_.groupBy(data.games, function(game) {
return game.type
}), function(typedGames, type) {
html += '<tr><td><h3>' + (
type === 'top' ? 'Top' :
type === 'flash' ? 'Ventes flash' :
'Offres du jour'
) + '</h3>'
_.each(typedGames, function(game, i) {
console.log(game.name + ' | ' + JSON.stringify(game))
game.timeLeft = game.timeLeft ? moment().add(game.timeLeft) :
endSaleDay
html += template(game)
})
})
html += '</table>Prochain refresh <b>' + moment().add(nextRefresh).fromNow() + '</b>.'
var mailOptions = {
from : 'whateva'
, to : '[email protected]'
, subject: 'Soldes Steam'
, html : html
}
smtpTransport.sendMail(mailOptions)
setTimeout(loop, nextRefresh)
})
})
}
loop()
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment