1
0
Fork 0
This commit is contained in:
boyska 2022-02-02 10:16:12 +01:00
parent 303819879d
commit 52cf3c5387
2 changed files with 149 additions and 25 deletions

View file

@ -1,6 +1,11 @@
const ICAL = require('ical.js')
const shows = require('./shows.js')
function max(a, b) {
if (a<b) return b
return a
}
/**
* Represent a schedule (ie: a .ics file)
*/
@ -21,26 +26,9 @@ class RadioSchedule {
}
/**
* @returns {external:ICAL~Component} if nothing is going on right now, `null` is returned
* @returns {RadioShow} tries to get a matching show, or create a new one
*/
getNowEvent(now) {
var ev_now = this.getEvents().filter(function(vevent) {
const ev = new ICAL.Event(vevent)
return isNow(ev, now)
})
if(ev_now.length === 0)
return null
if(ev_now.length > 1)
console.log("More than one event right now?!")
return ev_now[0]
}
/**
* @returns {RadioShow} if nothing is going on right now, `null` is returned
*/
getNowShow(now) {
var ev = this.getNowEvent(now)
getShowByEvent(ev) {
if (ev === null) return null
if (this.radio !== undefined) {
const showid = RadioSchedule.veventGetShowID(ev)
@ -54,19 +42,59 @@ class RadioSchedule {
}
/**
* @todo To be implemented
* @returns {external:ICAL~Component} if nothing is going on right now, `null` is returned
*/
getNowEvent(now) {
var ev_now = this.getEvents().filter(function(vevent) {
const ev = new ICAL.Event(vevent)
return isNow(ev, now)
})
ev_now.sort((e1, e2) => { return this.veventGetPriority(e1) - this.veventGetPriority(e2) })
if(ev_now.length === 0)
return null
return ev_now[0]
}
/**
* @returns {RadioShow} if nothing is going on right now, `null` is returned
*/
getNowShow(now) {
const ev = this.getNowEvent(now)
return this.getShowByEvent(ev)
}
/**
* @returns {NextEvent} if there is none, `null` is returned
*/
getNextEvent(now) {
// XXX
var nowEvent = this.getNowEvent(now)
let future_events = this.getEvents().filter((e) => { return e != nowEvent })
.map((e) => {
const vEvent = new ICAL.Event(e)
return {event: e, time: getNext(vEvent, now)}
})
.filter((x) => { return x.time !== null && x.time !== undefined })
// since ".sort()" is guaranteed to be stable, we can sort by priority, then by date, so that two events
// starting at the same time will be sorted observing priority
future_events.sort((x1, x2) => this.veventGetPriority(x1.event) - this.veventGetPriority(x2.event))
future_events.sort((x, y) => x.time.toUnixTime() - y.time.toUnixTime())
if (future_events.length === 0) {
return null
}
return future_events[0]
}
/**
* @todo To be implemented
* @returns {NextShow} if there is no next show, nothing will be returned
* @returns {NextShow} if there is no next show, null will be returned
*/
getNextShow(now) {
// XXX
const next = this.getNextEvent(now)
if (next === null) return null
const ev = next.event
const show = this.getShowByEvent(ev)
return {show: show, time: next.time}
}
static veventGetSummary(vevent) {
return vevent.getFirstProperty('summary').getFirstValue()
@ -75,6 +103,24 @@ class RadioSchedule {
return RadioSchedule.veventGetSummary(vevent) // XXX: X-Show-ID
}
/**
* @return {integer} a normalized version of priority, easier to compare
*/
veventGetPriority(ev) {
const prop = ev.getFirstProperty('priority')
let prio;
if (prop === null) {
prio = null
} else {
prio = prop.getFirstValue()
}
if (prio === null || prio === 0) {
prio = 100
}
return prio
}
}
@ -85,7 +131,7 @@ function isNow(vEvent, now) {
if (vEvent.isRecurring()) {
return isNowRecurring(vEvent, now)
}
return (now < vEvent.endDate) && (now > event.startDate);
return (now < vEvent.endDate) && (now > vEvent.startDate);
}
@ -105,6 +151,49 @@ function isNowRecurring(vEvent, now) {
}
/*
* @private
* @param {external:ICAL~Component} vEvent a _recurring_ vEvent
* @param {external:ICAL~Time} [now]
* @return {external:ICAL~Time} first future occurrence of this event
*/
function getNext(vEvent, now) {
if (now === undefined) {
now = ICAL.Time.now()
}
if (vEvent.isRecurring()) {
return getNextRecurring(vEvent, now)
}
if (vEvent.endDate > now) {
const val = max(now, vEvent.startDate)
return val
}
return null
}
/*
* @private
* @param {external:ICAL~Component} vEvent a _recurring_ vEvent
* @param {external:ICAL~Time} now
* @return {external:ICAL~Time} first future occurrence of this event
*/
function getNextRecurring(vEvent, now) {
var expand = vEvent.iterator(vEvent.startDate)
var next, next_end;
while ((next = expand.next())) {
const start = next.clone()
next_end = start.clone()
next_end.addDuration(vEvent.duration)
if (next_end <= now) {
continue
}
return max(start, now)
}
return null
}
async function get(manifest) {
if (manifest.scheduleURL) {
let resp = null
@ -151,6 +240,12 @@ module.exports = {
* @property {external:ICAL~Time} time When it will start
*/
/**
* @typedef {Object} NextEvent
* @property {RadioShow} event The next show scheduled
* @property {external:ICAL~Time} time When it will start
*/
/**
* @external ICAL
* @see https://mozilla-comm.github.io/ical.js/api/index.html

View file

@ -72,6 +72,35 @@ describe('examples/' + exampleName, () => {
assert.equal(show.getFeed(), testFeed)
})
it('monday at 7PM, "Entropia Massima" is next', async () => {
const rm = await radiomanifest.get(url)
const rs = rm.getSchedule()
const now = new ICAL.Time({
year: 2022,
month: 1,
day: 31,
hour: 19,
minute: 10,
second: 0,
isDate: false
},
);
const vevent = rs.getNowEvent(now)
assert.notEqual(vevent, null)
const show = rs.getNowShow(now)
assert.notEqual(show, null)
assert.equal(show.getName(), 'Baraonda')
const next_event = rs.getNextEvent(now)
assert.notEqual(next_event, null)
assert.notEqual(next_event.event, null)
const next_show = rs.getNextShow(now)
assert.notEqual(next_show, null)
assert.notEqual(next_show.show, null)
assert.equal(next_show.show.getName(), testShowName)
assert.equal(next_show.show.getFeed(), testFeed)
})
})
})