import { GuildScheduledEvent, Message, MessageCreateOptions, TextChannel } from "discord.js"; import { ScheduledTask, schedule } from "node-cron"; import { v4 as uuid } from "uuid"; import { client, jellyfinHandler } from "../.."; import { closePoll } from "../commands/closepoll"; import { config } from "../configuration"; import { logger } from "../logger"; import toDate from "date-fns/fp/toDate"; import { addDays, isAfter, isBefore } from "date-fns"; export const name = 'guildScheduledEventCreate' export enum Emotes { "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣", "🔟" } export let task: ScheduledTask | undefined export async function execute(event: GuildScheduledEvent) { const requestId = uuid() logger.debug(`New event created: ${JSON.stringify(event, null, 2)}`, { guildId: event.guildId, requestId }) if (event.name.toLowerCase().includes("!nextwp")) { logger.info("Event was a placeholder event to start a new watchparty and voting. Creating vote!", { guildId: event.guildId, requestId }) logger.debug("Renaming event", { guildId: event.guildId, requestId }) event.edit({ name: "Watchparty - Voting offen" }) const movies = await jellyfinHandler.getRandomMovies(5, event.guildId, requestId) logger.info(`Got ${movies.length} random movies. Creating voting`, { guildId: event.guildId, requestId }) logger.debug(`Movies: ${JSON.stringify(movies.map(movie => movie.name))}`, { guildId: event.guildId, requestId }) const announcementChannel: TextChannel = client.getAnnouncementChannelForGuild(event.guildId) logger.debug(`Found channel ${JSON.stringify(announcementChannel, null, 2)}`, { guildId: event.guildId, requestId }) let message = `[Abstimmung]\n<@&${config.bot.announcement_role}> Es gibt eine neue Abstimmung für die nächste Watchparty! Stimme hierunter für den nächsten Film ab!\n` for (let i = 0; i < movies.length; i++) { message = message.concat(Emotes[i]).concat(": ").concat(movies[i].name!).concat("\n") } const options: MessageCreateOptions = { allowedMentions: { parse: ["roles"]}, content: message } const sentMessage: Message = await (await announcementChannel.fetch()).send(options) for (let i = 0; i < movies.length; i++) { sentMessage.react(Emotes[i]) } if (!task) { task = schedule("0 * * * * *", () => checkForPollsToClose(event)) } // sentMessage.pin() //todo: uncomment when bot has permission to pin messages. Also update closepoll.ts to only fetch pinned messages } } async function checkForPollsToClose(event: GuildScheduledEvent): Promise { const requestId = uuid() logger.info(`Automatic check for poll closing.`, { guildId: event.guildId, requestId }) if (!event.guild) { logger.error("No guild in event. Cancelling.", { guildId: event.guildId, requestId }) return } //refetch event in case the time changed or the poll is already closed const events = (await event.guild.scheduledEvents.fetch()) .filter(event => event.name.toLowerCase().includes("voting offen")) .map((value, _) => value) if (!events || events.length <= 0) { logger.info("Did not find any events. Cancelling", { guildId: event.guildId, requestId }) return } else if (events.length > 1) { logger.error(`More than one event found. Don't know which one is the right one :( Events: ${JSON.stringify(events, null, 2)}`, { guildId: event.guildId, requestId }) return } const updatedEvent = events[0] //add two hours because of different timezones in discord api and Date.now() if (!updatedEvent.scheduledStartTimestamp) { logger.error("Event does not have a scheduled start time. Cancelling", { guildId: event.guildId, requestId }) return } const eventDate: Date = toDate(updatedEvent.scheduledStartTimestamp) const closePollDate: Date = addDays(eventDate, -2) if (isAfter(Date.now(), closePollDate)) { logger.info("Less than two days until event. Closing poll", { guildId: event.guildId, requestId }) closePoll(event.guild, requestId) } else { logger.info(`ScheduledStart: ${closePollDate}. Now: ${toDate(Date.now())}`, { guildId: event.guildId, requestId }) } }