2018-12-18 17:38:18 +00:00
|
|
|
const fs = require('fs')
|
|
|
|
const path = require('path')
|
|
|
|
const c = require('canvas')
|
|
|
|
|
|
|
|
const config = require(path.join(__dirname, 'config.js'))
|
|
|
|
const request = require(path.join(__dirname, 'request.js'))
|
|
|
|
|
|
|
|
function pz (z) {
|
|
|
|
if (z < 10) {
|
|
|
|
return '0' + z
|
|
|
|
}
|
|
|
|
return z
|
|
|
|
}
|
|
|
|
|
|
|
|
function dateFormat (date, yr) {
|
|
|
|
return (yr ? (date.getDate() + '/' + (date.getMonth() + 1) + '/' + date.getFullYear() + ' ') : '') +
|
|
|
|
pz(date.getHours()) + ':' + pz(date.getMinutes())
|
|
|
|
}
|
|
|
|
|
|
|
|
class Drawer {
|
2019-01-11 02:27:56 +00:00
|
|
|
constructor () {
|
|
|
|
this.canvas = c.createCanvas(config.calendar.schedule.width, config.calendar.schedule.height)
|
2018-12-18 17:38:18 +00:00
|
|
|
this.ctx = this.canvas.getContext('2d')
|
|
|
|
}
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
async draw (cal) {
|
2018-12-18 17:38:18 +00:00
|
|
|
let ctx = this.ctx
|
2019-01-11 02:27:56 +00:00
|
|
|
let font = config.calendar.schedule.font
|
|
|
|
let fontColor = config.calendar.schedule.fontColor
|
|
|
|
|
2018-12-18 17:38:18 +00:00
|
|
|
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.fillStyle = config.calendar.schedule.background
|
2018-12-18 17:38:18 +00:00
|
|
|
ctx.fillRect(5, 5, this.canvas.width - 10, this.canvas.height - 10)
|
|
|
|
|
|
|
|
let added = 0
|
|
|
|
|
|
|
|
for (let i in cal.events) {
|
|
|
|
let ev = cal.events[i]
|
|
|
|
|
|
|
|
if (i > 5) break // Can't fit so many on here :P
|
|
|
|
if (ev.eventStartTime < Date.now() || ev.eventEndTime < Date.now()) continue
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.fillStyle = fontColor
|
2018-12-18 17:38:18 +00:00
|
|
|
let y = (i * 60) + 30
|
|
|
|
|
|
|
|
// Write event name
|
|
|
|
let evn = ev.eventName
|
|
|
|
if (evn.length > 14) {
|
|
|
|
evn = evn.substring(0, 14) + '…'
|
|
|
|
}
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.font = '26px ' + font
|
2018-12-18 17:38:18 +00:00
|
|
|
ctx.fillText(evn, 10, y)
|
|
|
|
|
|
|
|
// Write event description
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.font = '16px ' + font
|
2018-12-18 17:38:18 +00:00
|
|
|
ctx.fillText(ev.description, 10, y + 20)
|
|
|
|
|
|
|
|
// Write event time
|
|
|
|
let time = dateFormat(ev.eventStartTime)
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.font = '26px ' + font
|
2018-12-18 17:38:18 +00:00
|
|
|
let tlen = ctx.measureText(time).width
|
|
|
|
ctx.fillText(time, (this.canvas.width - 10) - tlen, y)
|
|
|
|
|
|
|
|
// Draw line under text
|
|
|
|
ctx.strokeStyle = 'rgba(0,0,0,0.5)'
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.lineTo(10, y + 20 + 12)
|
|
|
|
ctx.lineTo(this.canvas.width - 10, y + 20 + 12)
|
|
|
|
ctx.stroke()
|
|
|
|
added++
|
|
|
|
}
|
|
|
|
|
|
|
|
if (added === 0) {
|
2019-01-11 02:27:56 +00:00
|
|
|
ctx.fillStyle = fontColor
|
|
|
|
ctx.font = '26px ' + font
|
2018-12-18 17:38:18 +00:00
|
|
|
ctx.fillText('No events scheduled.', 10, 35)
|
|
|
|
}
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
await this.toFile()
|
2018-12-18 17:38:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
toFile () {
|
|
|
|
const out = fs.createWriteStream(path.join(process.env.PWD, 'liq', 'schedule.png'))
|
|
|
|
const stream = this.canvas.createPNGStream()
|
|
|
|
stream.pipe(out)
|
|
|
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
out.on('finish', resolve)
|
|
|
|
out.on('error', reject)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Calendar {
|
|
|
|
constructor (conf) {
|
|
|
|
this.events = []
|
|
|
|
|
|
|
|
this.config = conf
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
this.drawer = new Drawer()
|
2018-12-18 17:38:18 +00:00
|
|
|
this.schedRunner = null
|
2019-01-11 02:27:56 +00:00
|
|
|
this.schedReload = null
|
2018-12-18 17:38:18 +00:00
|
|
|
|
|
|
|
this.started = []
|
|
|
|
this.timers = { a: null, b: null, c: null }
|
|
|
|
}
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
update () {
|
|
|
|
this.drawer.draw(this).then(() => {
|
|
|
|
setTimeout(() => {
|
|
|
|
this.schedReload && this.schedReload.call(this, this)
|
|
|
|
}, 1000)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-12-18 17:38:18 +00:00
|
|
|
startTimers () {
|
|
|
|
// Initial run
|
|
|
|
this.calendarFetch().then(
|
2019-01-11 02:27:56 +00:00
|
|
|
(e) => this.update(),
|
2018-12-18 17:38:18 +00:00
|
|
|
(e) => console.error('Calendar fetch failed!', e.stack)
|
|
|
|
)
|
|
|
|
|
|
|
|
// Set timers
|
|
|
|
this.timers = {
|
|
|
|
a: setInterval(() => this.calendarFetch().catch((e) => console.error('Calendar fetch failed!', e.stack)), this.config.interval * 1000),
|
|
|
|
b: setInterval(() => this.runners(), 60 * 1000),
|
2019-01-11 02:27:56 +00:00
|
|
|
c: setInterval(() => this.update(), 120 * 1000)
|
2018-12-18 17:38:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stopTimers () {
|
|
|
|
clearInterval(this.timers.a)
|
|
|
|
clearInterval(this.timers.b)
|
|
|
|
clearInterval(this.timers.c)
|
|
|
|
}
|
|
|
|
|
|
|
|
static sortStartTime (a, b) {
|
|
|
|
return a.eventStartTime - b.eventEndTime
|
|
|
|
}
|
|
|
|
|
|
|
|
static prettifyEvent (item) {
|
|
|
|
let ev = {
|
|
|
|
id: item.id,
|
|
|
|
htmlLink: item.htmlLink,
|
|
|
|
created: new Date(item.created),
|
|
|
|
updated: new Date(item.updated),
|
|
|
|
|
|
|
|
title: item.summary.replace(/\n/g, ' '),
|
|
|
|
location: item.location,
|
|
|
|
description: (item.description || '').replace(/\n/g, ' '),
|
|
|
|
|
|
|
|
start: new Date(item.start.dateTime || item.start.date),
|
|
|
|
end: new Date(item.end.dateTime || item.end.date),
|
|
|
|
sequence: item.sequence
|
|
|
|
}
|
|
|
|
|
|
|
|
ev.length = (ev.end.getTime() - ev.start.getTime()) / 1000
|
|
|
|
|
|
|
|
return ev
|
|
|
|
}
|
|
|
|
|
|
|
|
async calendarFetch () {
|
|
|
|
const timeFrame = this.config.timeFrame
|
|
|
|
const cUrl = this.config.calendar
|
|
|
|
const apiKey = this.config.googleKey
|
|
|
|
|
|
|
|
let now = Date.now()
|
|
|
|
let url = 'https://www.googleapis.com/calendar/v3/calendars/' + encodeURIComponent(cUrl) + '/events?key=' + apiKey +
|
|
|
|
'&timeMin=' + (new Date(now - 10 * 60 * 1000).toISOString()) +
|
|
|
|
'&timeMax=' + (new Date(now + timeFrame * 1000).toISOString()) + '&singleEvents=true'
|
|
|
|
|
|
|
|
let data = await request.GET(url)
|
|
|
|
data = JSON.parse(data)
|
|
|
|
now = Date.now()
|
|
|
|
|
|
|
|
if (!data.items) return
|
|
|
|
let results = []
|
|
|
|
|
|
|
|
for (let i = 0; i < data.items.length; i++) {
|
|
|
|
let item = Calendar.prettifyEvent(data.items[i])
|
|
|
|
|
|
|
|
if (now < item.end.getTime()) {
|
|
|
|
let desc = item.description
|
|
|
|
let scr = null
|
|
|
|
if (desc.indexOf('$:') !== -1) {
|
|
|
|
let a = desc.split('$:')
|
|
|
|
desc = a[0].trim()
|
|
|
|
scr = a[1].trim()
|
|
|
|
}
|
|
|
|
|
|
|
|
results.push({
|
|
|
|
id: item.id,
|
|
|
|
eventName: item.title,
|
|
|
|
eventStartTime: item.start,
|
|
|
|
eventEndTime: item.end,
|
|
|
|
description: desc,
|
|
|
|
descriptor: scr
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[schedule] Calendar fetched successfully!`)
|
|
|
|
|
|
|
|
this.events = results.sort(Calendar.sortStartTime)
|
|
|
|
}
|
|
|
|
|
|
|
|
set runner (runner) {
|
|
|
|
this.schedRunner = runner
|
|
|
|
}
|
|
|
|
|
2019-01-11 02:27:56 +00:00
|
|
|
set reload (reload) {
|
|
|
|
this.schedReload = reload
|
|
|
|
}
|
|
|
|
|
2018-12-18 17:38:18 +00:00
|
|
|
runners () {
|
|
|
|
if (!this.schedRunner) return
|
|
|
|
for (let i in this.events) {
|
|
|
|
let ev = this.events[i]
|
|
|
|
if (!ev.descriptor) continue
|
|
|
|
if (ev.eventStartTime < Date.now() && ev.eventEndTime > Date.now()) {
|
|
|
|
if (this.started.indexOf(ev.id) !== -1) continue
|
|
|
|
console.log(`[schedule] Starting event ${ev.eventName}..`)
|
|
|
|
|
|
|
|
this.started.push(ev.id)
|
|
|
|
this.schedRunner.call(this, ev)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = Calendar
|