Skip to content

Instantly share code, notes, and snippets.

@rystaf
Created December 8, 2021 02:19
Show Gist options
  • Save rystaf/31fb3b699b6c0a696311a7309986fb33 to your computer and use it in GitHub Desktop.
Save rystaf/31fb3b699b6c0a696311a7309986fb33 to your computer and use it in GitHub Desktop.
const fs = require('fs')
const https = require('https')
const querystring = require('querystring')
const ord = (i) => {
const j = i % 10,
k = i % 100;
if (j == 1 && k != 11) return i + "st";
if (j == 2 && k != 12) return i + "nd";
if (j == 3 && k != 13) return i + "rd";
return i + "th";
}
const request = (options, postData) => new Promise((resolve, reject) => {
if (postData) {
var payload = querystring.stringify(postData)
options.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': payload.length,
...options.headers
}
}
const req = https.request(options, (response) => {
let data = ''
response.on('data', chunk => {
data = data + chunk.toString();
})
response.on('end', () => resolve(data))
})
req.on('error', (error) => reject(error))
if (postData) req.write(payload)
req.end();
})
const main = async () => {
const config = require('./config.json')
const now = new Date()
console.log(now, 'fetching leaderboard')
const lb = JSON.parse(await request({
hostname: 'adventofcode.com',
port: 443,
path: `/${now.getFullYear()}/leaderboard/private/view/${config.leaderboardID}.json`,
method: 'GET',
headers: {
'Cookie': `session=${config.session}`
}
}))
const members = Object.keys(lb.members).map(id => {
const {name, completion_day_level: days, local_score, stars} = lb.members[id]
const solves = Array.apply(null, Array(now.getDate())).map((x,i)=> i+1).map(d => {
const parts = Object.keys(days[d]||{}).map(x => parseInt(x))
return ['1','2'].map(p => {
const t = (days[d]||{})[p]?.get_star_ts
return t ? new Date(1000 * t) : t
})
})
return {name, solves, local_score, stars}
}).sort((a,b)=> b.local_score-a.local_score)
if (!fs.existsSync('./cache.json')) {
return fs.writeFileSync(`./cache.json`, JSON.stringify(members, null, 2))
}
const cache = require('./cache.json')
const updates = members.flatMap((m, mi) => {
const rank = mi + 1
const mcache = cache.find(x => x.name == m.name)
const oldrank = cache.findIndex(x => x.name == m.name) + 1
if (!mcache) {
return `*${m.name}* has joined the leaderboard with ${m.stars} star${m.stars != 1 ? 's':''}, which puts them in ${ord(rank)} place.`
}
const newSolves = m.solves
.map((s,d) => ({
name: m.name,
day: d + 1,
timestamps: s,
rank: s.map((x,p) => {
return [...members].sort((a,b) => a.solves[d][p] - b.solves[d][p]).findIndex(mm => mm.name == m.name)
})
}))
.filter((s, d) => {
return mcache.solves[d].filter(x => x).length != s.timestamps.filter(x => x).length
})
.map(s => {
const place = rank == oldrank
? `They are still in *${ord(rank)}* place.`
: `They moved from ${ord(oldrank)} place to *${ord(rank)}* place.`
let puzzle = s.day
let part = 1
if (!s.timestamps[1]) {
puzzle += ' part 1'
part = 0
}
return `*${m.name}* finished day ${puzzle}! They were the *${ord(s.rank[part]+1)}* person to do so. ${place}`
})
return newSolves
}).filter(x => x)
console.log(updates.join('\n'))
const response = request({
hostname: 'hooks.slack.com',
port: 443,
path: config.webhookPath,
method: 'POST',
}, {"payload": `{\"channel\": \"${config.channel}\", \"text\": \"${updates.map((x,i,s) => (s.length > 1 ? "• ":"")+x).join('\n')}\"}`})
fs.writeFileSync(`./cache.json`, JSON.stringify(members, null, 2))
}
main()
setInterval(main, 1000 * 60 * 15)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment