icytv-liq/control/schedule.js

222 lines
5.7 KiB
JavaScript

const fs = require('fs')
const path = require('path')
const c = require('canvas')
const EventEmitter = require('events').EventEmitter
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 {
constructor () {
this.canvas = c.createCanvas(config.calendar.schedule.width, config.calendar.schedule.height)
this.ctx = this.canvas.getContext('2d')
}
async draw (cal) {
let ctx = this.ctx
let font = config.calendar.schedule.font
let fontColor = config.calendar.schedule.fontColor
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
ctx.fillStyle = config.calendar.schedule.background
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
ctx.fillStyle = fontColor
let y = (i * 60) + 30
// Write event name
let evn = ev.eventName
if (evn.length > 14) {
evn = evn.substring(0, 14) + '…'
}
ctx.font = '26px ' + font
ctx.fillText(evn, 10, y)
// Write event description
ctx.font = '16px ' + font
ctx.fillText(ev.description, 10, y + 20)
// Write event time
let time = dateFormat(ev.eventStartTime)
ctx.font = '26px ' + font
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) {
ctx.fillStyle = fontColor
ctx.font = '26px ' + font
ctx.fillText('No events scheduled.', 10, 35)
}
await this.toFile()
}
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 extends EventEmitter {
constructor (conf) {
super()
this.events = []
this.config = conf
this.drawer = new Drawer()
this.started = []
this.timers = { a: null, b: null, c: null }
}
update () {
this.drawer.draw(this).then(() => this.emit('reload'))
}
startTimers () {
// Initial run
this.calendarFetch().then(
(e) => this.update(),
(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),
c: setInterval(() => this.update(), 120 * 1000)
}
}
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)
this.emit('events', this.events)
}
runners () {
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.emit('event-start', ev)
}
}
}
}
module.exports = Calendar