radiobot/modules/event.js
2022-03-22 20:25:39 -04:00

514 lines
12 KiB
JavaScript

var fs = require("fs");
var moment = require("moment");
var cmdsplit = require("./../cmdsplit");
class EventSchedule
{
constructor(config, client, bot)
{
this.event = config;
this.client = client;
this.bot = bot;
this.lastNotFound = new Date(1970, 1, 1);
this.lastNow = new Date(1970, 1, 1);
this.loadSchedule(this.event.file);
}
loadSchedule(filename)
{
console.log('Loading schedule: "' + filename + '"');
this.schedule = JSON.parse(fs.readFileSync(filename));
for (var i = 0; i < this.schedule.length; i++) {
let stage = this.schedule[i];
console.log("Event channel: " + stage.channel);
this.client.channels.fetch(stage.channel).then(channel => {
stage.channel = channel;
this.updateChannel(stage);
}).catch(() => {
console.error("Unable to find channel for stage \"" + stage.stage + "\"");
});
var newResponses = [];
for (var expression in stage.responses) {
let newResponse = {
match: new RegExp(expression, "i"),
msg: stage.responses[expression]
};
newResponses.push(newResponse);
}
stage.responses = newResponses;
stage.channelExtra = null;
if (stage.extra_channel !== undefined) {
this.client.channels.fetch(stage.extra_channel).then(channel => {
stage.channelExtra = channel;
}).catch(() => {
console.error("Unable to find channel for stage \"" + stage.stage + "\"");
});
}
var streamDelay = stage.streamdelay;
for (var j = 0; j < stage.sets.length; j++) {
var set = stage.sets[j];
var dateArray = set.slice(0, 5);
dateArray[1] -= 1; // months are 0-indexed, for some reason. even in the moment library!
var setDate = moment(dateArray).add(streamDelay, 'm');
var newSet = {
date: setDate,
name: set[5],
report: moment() > setDate,
report_5min: moment().add(5, 'm') > setDate,
nothing: (set[5] === undefined || set[5] == "Nothing"),
who: set[6]
};
stage.sets[j] = newSet;
}
}
}
getStage(stage)
{
for (var i = 0; i < this.schedule.length; i++) {
var s = this.schedule[i];
if (s.stage == stage) {
return s;
}
}
return null;
}
getStageByChannel(channel)
{
for (var i = 0; i < this.schedule.length; i++) {
var s = this.schedule[i];
if (s.channel == channel) {
return s;
}
}
return null;
}
findSets(query)
{
query = query.toLowerCase();
var ret = [];
for (var i = 0; i < this.schedule.length; i++) {
var stage = this.schedule[i];
for (var j = 0; j < stage.sets.length; j++) {
var set = stage.sets[j];
if (set.nothing) {
continue;
}
if (set.name.toLowerCase().indexOf(query) != -1 || (set.who && set.who.toLowerCase().indexOf(query) != -1)) {
ret.push({
set: set,
stage: stage
});
}
}
}
return ret;
}
getCurrentSet(stage)
{
var date = new Date();
for (var i = 0; i < stage.sets.length; i++) {
var set = stage.sets[i];
if (date < set.date) {
if (i == 0) {
// Happens if no set has started yet on this stage
return null;
}
return stage.sets[i - 1];
}
}
// Happens if the last set has been played
return stage.sets[stage.sets.length - 1];
}
getNextSet(stage)
{
var date = new Date();
for (var i = 0; i < stage.sets.length; i++) {
var set = stage.sets[i];
if (date < set.date) {
return set;
}
}
// Happens if this is the final set on this stage
return null;
}
getNextLiveSet(stage)
{
var date = new Date();
for (var i = 0; i < stage.sets.length; i++) {
var set = stage.sets[i];
if (date < set.date && !set.nothing) {
return set;
}
}
// Happens if this is the final set on this stage
return null;
}
onTick()
{
var date = moment();
for (var i = 0; i < this.schedule.length; i++) {
var stage = this.schedule[i];
var current = this.getCurrentSet(stage);
if (current !== null) {
if (!current.report) {
current.report = true;
if (!current.nothing) {
console.log("Starting now: " + current.name);
var msg = ":red_circle: STARTING NOW: **" + current.name + "**";
stage.channel.send(msg);
if (stage.channelExtra) {
stage.channelExtra.send(msg);
}
} else {
console.log("Stream is not live anymore.");
var next = this.getNextSet(stage);
if (next !== null && !next.nothing) {
var msg = ":no_entry_sign: Stream is no longer live. Next set is at **" + this.getTimeString(next.date) + "**!";
stage.channel.send(msg);
if (stage.channelExtra) {
stage.channelExtra.send(msg);
}
} else {
var msg = ":tada: This is the end of the livestream. Thanks for watching.";
stage.channel.send(msg);
if (stage.channelExtra) {
stage.channelExtra.send(msg);
}
}
}
this.updateChannel(stage);
}
}
var next = this.getNextSet(stage);
if (next !== null && !next.nothing) {
if (date.clone().add(5, 'm') > next.date && !next.report_5min) {
next.report_5min = true;
console.log("Starting in 5 minutes: " + next.name);
var msg = ":warning: **" + next.name + "** starts in 5 minutes!";
stage.channel.send(msg);
if (stage.channelExtra) {
stage.channelExtra.send(msg);
}
}
}
}
}
onCmdCurrent(msg) { this.onCmdNp(msg); }
onCmdNow(msg) { this.onCmdNp(msg); }
onCmdNp(msg)
{
var stage = this.getStageByChannel(msg.channel);
if (!stage) {
return;
}
var current = this.getCurrentSet(stage);
if (current !== null && !current.nothing) {
if (current.who) {
msg.channel.send(":red_circle: Now playing: **" + current.name + "**, started <t:" + current.date.unix() + ":R>! (" + current.who + ")");
} else {
msg.channel.send(":red_circle: Now playing: **" + current.name + "**, started <t:" + current.date.unix() + ":R>!");
}
} else {
msg.channel.send("Nobody's playing right now.");
}
}
onCmdNext(msg)
{
var stage = this.getStageByChannel(msg.channel);
if (!stage) {
return;
}
var next = this.getNextSet(stage);
if (next) {
var localTime = "**" + this.getTimeString(next.date) + "**";
localTime += " (<t:" + next.date.unix() + ":R>)";
if (next.name) {
if (next.who) {
msg.channel.send(":arrow_forward: Next up: **" + next.name + "**, at " + localTime + " (" + next.who + ")");
} else {
msg.channel.send(":arrow_forward: Next up: **" + next.name + "**, at " + localTime);
}
} else {
msg.channel.send(":arrow_forward: The stream ends at " + localTime);
}
} else {
msg.channel.send("There's nothing playing next.");
}
}
getScheduleString(stage, limit, starttime)
{
var ret = "";
if (stage.unconfirmed) {
ret = ":warning: **Note:** Set times are not confirmed!\n";
}
if (!starttime) {
starttime = moment(stage.sets[0].date).clone().subtract(1, 'm');
}
var lines = 0;
for (var i = 0; i < stage.sets.length; i++) {
var set = stage.sets[i];
if (starttime > set.date) {
continue;
}
if (limit && lines == limit) {
ret += "(limited, use `.fullschedule` for the full schedule)\n";
break;
}
lines++;
if (set.nothing) {
ret += "- <t:" + set.date.unix() + ":t> (<t:" + set.date.unix() + ":R>), the stream will be offline :no_entry_sign:\n";
} else {
if (set.who) {
ret += "- <t:" + set.date.unix() + ":t> (<t:" + set.date.unix() + ":R>): **" + set.name + "** (" + set.who + ")\n";
} else {
ret += "- <t:" + set.date.unix() + ":t> (<t:" + set.date.unix() + ":R>): **" + set.name + "**\n";
}
}
}
if (lines == 0) {
ret = "We have nothing left! :frowning:";
} else if (limit) {
ret = ":calendar_spiral: Next " + limit + " sets are:\n" + ret.trim();
} else {
ret = ":calendar_spiral: The full schedule:\n" + ret.trim();
}
return ret;
}
onCmdTimetable(msg) { this.onCmdSchedule(msg); }
onCmdSched(msg) { this.onCmdSchedule(msg); }
onCmdSchedule(msg)
{
var stage = this.getStageByChannel(msg.channel);
if (!stage) {
return;
}
msg.channel.send(this.getScheduleString(stage, 5, moment()));
}
onCmdFullSched(msg) { this.onCmdFullSchedule(msg); }
onCmdFullSchedule(msg)
{
var stage = this.getStageByChannel(msg.channel);
if (!stage) {
return;
}
var text = this.getScheduleString(stage);
while (text.length > 0) {
msg.author.send(text.substr(0, 2000)).catch(console.error);
text = text.substr(2000);
}
msg.reply("I've DM'd you the full schedule.");
}
onCmdFind(msg)
{
var query = Array.from(arguments).slice(1).join(" ").trim();
if (query.length < 3) {
return;
}
var results = this.findSets(query);
var ret = "";
if (results.length == 0) {
ret = "I found nothing :frowning:";
// Avoid spamming "I found nothing" when jokers do .find a meaning of life
var now = new Date();
if ((now - this.lastNotFound) < 60 * 1000) {
return;
}
this.lastNotFound = now;
} else {
var date = new Date();
for (var i = 0; i < results.length; i++) {
var res = results[i];
var localTime = "**" + this.getTimeString(res.set.date) + "**";
localTime += " (<t:" + res.set.date.unix() + ":R>)";
var stageMessage = "";
if (this.schedule.length > 1) {
stageMessage = " on **" + res.stage.stage + "** " + res.stage.emoji + " stage!";
}
if (date > res.date) {
ret += res.set.name + " already played on <t:" + res.set.date.unix() + ":F>\n";
} else {
ret += res.set.name + " plays on <t:" + res.set.date.unix() + ":F>\n";
}
}
}
msg.channel.send(":calendar_spiral: " + ret.trim());
}
onCmdReloadSchedule(msg)
{
if (!this.bot.isAdmin(msg.member)) {
return;
}
this.loadSchedule(this.event.file);
msg.reply("schedule reloaded!");
}
onMessage(msg)
{
var inStage = false;
for (var i = 0; i < this.schedule.length; i++) {
var stage = this.schedule[i];
if (stage.channel.id != msg.channel.id) {
continue;
}
inStage = true;
for (var j = 0; j < stage.responses.length; j++) {
var r = stage.responses[j];
var match = msg.content.match(r.match);
if (match) {
var sendMessage = r.msg;
for (var k = 0; k < match.length; k++) {
sendMessage = sendMessage.replace("$" + k, match[k]);
}
msg.channel.send(sendMessage);
return true;
}
}
}
var isCommand = msg.content.startsWith(".");
var parse = [];
if (isCommand) {
parse = cmdsplit(msg.content);
}
// Outside-channel schedule command
if (isCommand && this.schedule.length > 1 && !inStage && (parse[0] == ".schedule" || parse[0] == ".timetable" || parse[0] == ".sched" || parse[0] == ".current" || parse[0] == ".now")) {
// Avoid spamming long .now message when jokers spam .now
var now = new Date();
if ((now - this.lastNow) < 60 * 1000) {
return true;
}
this.lastNow = now;
var ret = "**LIVE**\n";
for (var i = 0; i < this.schedule.length; i++) {
var stage = this.schedule[i];
var current = this.getCurrentSet(stage);
var next = this.getNextSet(stage);
if (current === null && next !== null && next.date.date() != moment(now).date()) {
continue;
}
if (current !== null && !current.nothing) {
ret += stage.emoji + " " + stage.stage + ": **" + current.name + "**";
} else {
ret += stage.emoji + " " + stage.stage + ": Not live";
}
if (next !== null && !next.nothing) {
ret += ", next: " + next.name;
} else {
ret += ".";
}
ret += " " + stage.channel.toString() + "\n";
}
msg.channel.send(ret.trim());
return true;
}
return false;
}
getTimeString(date)
{
return "<t:" + date.unix() + ":t>";
}
updateChannel(stage)
{
if (typeof(stage.channel) == "string") {
return;
}
var line = "";
var current = this.getCurrentSet(stage);
var next = this.getNextLiveSet(stage);
if ((current === null || current.nothing) && next === null) {
line += " :tada: Thanks for watching.";
} else {
if (current !== null && !current.nothing) {
line += " __" + current.name + "__ <t:" + current.date.unix() + ":R>";
} else {
line += " :no_entry_sign: __Not currently live__.";
}
if (next !== null) {
line += " :arrow_forward: Next: __" + next.name + "__ <t:" + next.date.unix() + ":R>";
} else {
line += " :warning: This is the last set!";
}
line += " :link: " + stage.url;
}
stage.channel.setTopic(stage.emoji + " " + line, "Automated bot action for event");
}
}
module.exports = EventSchedule;