23 Commits

Author SHA1 Message Date
a18406e7e4 1.0.3
Some checks failed
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Failing after 8s
2023-06-22 23:18:41 +02:00
b9f65125dc Hopefully fix ci/cd 2023-06-22 23:18:06 +02:00
d61457cb5f 1.0.2
Some checks failed
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Failing after 10s
2023-06-22 23:05:47 +02:00
8d0dda0fa9 Merge pull request 'fix/ci-tag' (#47) from fix/ci-tag into master
Reviewed-on: #47
2023-06-22 18:38:34 +02:00
777ae330ad remove master branch restriction on docker-build
All checks were successful
Compile the repository / compile (pull_request) Successful in 10s
since the pipeline is only ever called on a tag, which will by convention only be committed to the master branch, we can be reasonably sure
that we are on the correct branch.
Tags are independent on branches which makes it impossible to check for tag AND master branch ref at the same time.
2023-06-19 23:34:25 +02:00
111ccaa880 simplify the test compile
All checks were successful
Compile the repository / compile (pull_request) Successful in 11s
2023-06-19 23:28:39 +02:00
c00453d3d3 push all tags of an image
All checks were successful
Compile the repository / compile (pull_request) Successful in 11s
2023-06-19 23:26:56 +02:00
8a7973a2e3 compile only on PR 2023-06-19 23:26:41 +02:00
0b67b126dd 1.0.1
All checks were successful
Compile the repository / compile (push) Successful in 9s
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Has been skipped
2023-06-19 23:19:40 +02:00
6d5725be90 Merge pull request 'fix/movie_names_and_background_task' (#46) from fix/movie_names_and_background_task into master
All checks were successful
Compile the repository / compile (push) Successful in 11s
Reviewed-on: #46
2023-06-19 11:29:04 +02:00
59f5b34e5a Merge branch 'master' into fix/movie_names_and_background_task
All checks were successful
Compile the repository / compile (push) Successful in 1m31s
2023-06-19 11:19:17 +02:00
670a64af22 Check if less than 2 days between create and start for deciding if to close
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m9s
2023-06-17 13:18:52 +02:00
4cc332820f prevent poll close if event is less than 24h old
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m15s
2023-06-17 13:03:48 +02:00
f5928049ea Merge pull request 'fix and refactor mitgucken guide' (#44) from fix/guide into master
All checks were successful
Compile the repository / compile (push) Successful in 9s
Reviewed-on: #44
2023-06-17 12:17:29 +02:00
99905f98d0 Merge pull request 'fix/ci-cd-push' (#45) from fix/ci-cd-push into master
All checks were successful
Compile the repository / compile (push) Successful in 10s
Reviewed-on: #45
2023-06-17 12:16:13 +02:00
07849d331a move scheduling of pollclose task to startup
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m37s
Also moved check function to closepoll.ts
2023-06-17 12:00:14 +02:00
1e6a75687a add package version extraction to docker push job
All checks were successful
Compile the repository / compile (push) Successful in 9s
2023-06-17 01:31:03 +02:00
2c09033c3f add new tag restriction to docker push job
All checks were successful
Compile the repository / compile (push) Successful in 9s
2023-06-17 01:27:49 +02:00
ce4441cee3 add restriction to master branch on docker push job
All checks were successful
Compile the repository / compile (push) Successful in 9s
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Has been skipped
2023-06-17 01:22:53 +02:00
7c8072b295 add separate compile step
should be run on every push to a branch to check for compilability
2023-06-17 01:20:54 +02:00
7899aac5ce adjust server connection message
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m22s
remove extraneous repetition of the server address
2023-06-17 01:20:01 +02:00
26c2d91252 fix and refactor mitgucken guide
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m16s
- reorder account acquisition in front of login
- rebox explainrole function
- adjust external reference to function
2023-06-17 01:13:33 +02:00
d6300e8bec improve movie name resolving
All checks were successful
Build a docker image for node-jellyfin-role-bot / build-docker-image (push) Successful in 1m55s
When creating the poll the bot will now only request movie names instead of movies
This improves the errorhandling because the movie names cannot be null
Also the movieName function filters empty movienames and will guarantee the requested number of names
2023-06-16 20:15:36 +02:00
11 changed files with 116 additions and 77 deletions

View File

@ -0,0 +1,17 @@
name: Compile the repository
on: [pull_request]
env:
REGISTRY: gitea.brudi.xyz
IMAGE_NAME: ${{ gitea.repository }}
USER: ${{ gitea.actor }}
jobs:
compile:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Build Container
run: docker build .

View File

@ -1,6 +1,9 @@
name: Build a docker image for node-jellyfin-role-bot name: Build a docker image for node-jellyfin-role-bot
run-name: ${{ gitea.actor }} is building an image run-name: ${{ gitea.actor }} is building an image
on: [push] on:
push:
tags:
- '*'
env: env:
REGISTRY: gitea.brudi.xyz REGISTRY: gitea.brudi.xyz
IMAGE_NAME: ${{ gitea.repository }} IMAGE_NAME: ${{ gitea.repository }}
@ -8,6 +11,7 @@ env:
jobs: jobs:
build-docker-image: build-docker-image:
runs-on: ubuntu-latest runs-on: ubuntu-latest
#if: gitea.ref == 'refs/heads/master'
container: catthehacker/ubuntu:act-latest container: catthehacker/ubuntu:act-latest
permissions: permissions:
contents: read contents: read
@ -18,6 +22,6 @@ jobs:
- name: Log in to the Container registry - name: Log in to the Container registry
run: docker login -u ${{ env.USER }} -p ${{ secrets.TOKEN }} ${{ env.REGISTRY }} run: docker login -u ${{ env.USER }} -p ${{ secrets.TOKEN }} ${{ env.REGISTRY }}
- name: Build Container - name: Build Container
run: docker build -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" . run: docker build -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" -t "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ node -p "require('./package.json').version" }}".
- name: Push Container - name: Push Container
run: docker push "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" run: docker push --all-tags "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "node-jellyfin-discord-bot", "name": "node-jellyfin-discord-bot",
"version": "1.0.0", "version": "1.0.3",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "node-jellyfin-discord-bot", "name": "node-jellyfin-discord-bot",
"version": "1.0.0", "version": "1.0.3",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@discordjs/rest": "^1.7.0", "@discordjs/rest": "^1.7.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "node-jellyfin-discord-bot", "name": "node-jellyfin-discord-bot",
"version": "1.0.0", "version": "1.0.3",
"description": "A discord bot to sync jellyfin accounts with discord roles", "description": "A discord bot to sync jellyfin accounts with discord roles",
"main": "index.js", "main": "index.js",
"license": "MIT", "license": "MIT",

View File

@ -1,13 +1,13 @@
import { addDays, differenceInDays, format, isAfter, toDate } from 'date-fns'
import { Guild, GuildScheduledEvent, GuildScheduledEventEditOptions, GuildScheduledEventSetStatusArg, GuildScheduledEventStatus, Message, MessageCreateOptions, TextChannel } from 'discord.js' import { Guild, GuildScheduledEvent, GuildScheduledEventEditOptions, GuildScheduledEventSetStatusArg, GuildScheduledEventStatus, Message, MessageCreateOptions, TextChannel } from 'discord.js'
import { v4 as uuid } from 'uuid' import { v4 as uuid } from 'uuid'
import { client } from '../..' import { client } from '../..'
import { config } from '../configuration' import { config } from '../configuration'
import { Emotes } from '../events/guildScheduledEventCreate' import { Emotes } from '../events/guildScheduledEventCreate'
import { Maybe } from '../interfaces'
import { logger } from '../logger' import { logger } from '../logger'
import { Command } from '../structures/command' import { Command } from '../structures/command'
import { RunOptions } from '../types/commandTypes' import { RunOptions } from '../types/commandTypes'
import { format } from 'date-fns'
import { Maybe } from '../interfaces'
export default new Command({ export default new Command({
name: 'closepoll', name: 'closepoll',
@ -34,7 +34,7 @@ export async function closePoll(guild: Guild, requestId: string) {
logger.info("stopping poll", { guildId, requestId }) logger.info("stopping poll", { guildId, requestId })
const announcementChannel: Maybe<TextChannel> = client.getAnnouncementChannelForGuild(guildId) const announcementChannel: Maybe<TextChannel> = client.getAnnouncementChannelForGuild(guildId)
if(!announcementChannel) { if (!announcementChannel) {
logger.error("Could not find the textchannel. Unable to close poll.", { guildId, requestId }) logger.error("Could not find the textchannel. Unable to close poll.", { guildId, requestId })
return return
} }
@ -57,14 +57,14 @@ export async function closePoll(guild: Guild, requestId: string) {
const votes = await (await getVotesByEmote(lastMessage, guildId, requestId)) const votes = await (await getVotesByEmote(lastMessage, guildId, requestId))
.sort((a, b) => b.count - a.count) .sort((a, b) => b.count - a.count)
logger.debug(`votes: ${JSON.stringify(votes, null, 2)}`, { guildId, requestId }) logger.debug(`votes: ${JSON.stringify(votes, null, 2)}`, { guildId, requestId })
logger.info("Deleting vote message") logger.info("Deleting vote message")
await lastMessage.delete() await lastMessage.delete()
const event = await getEvent(guild, guild.id, requestId) const event = await getEvent(guild, guild.id, requestId)
if(event) { if (event) {
updateEvent(event, votes, guild, guildId, requestId) updateEvent(event, votes, guild, guildId, requestId)
sendVoteClosedMessage(event, votes[0].movie, guildId, requestId) sendVoteClosedMessage(event, votes[0].movie, guildId, requestId)
} }
@ -82,7 +82,7 @@ async function sendVoteClosedMessage(event: GuildScheduledEvent, movie: string,
} }
const announcementChannel = client.getAnnouncementChannelForGuild(guildId) const announcementChannel = client.getAnnouncementChannelForGuild(guildId)
logger.info("Sending vote closed message.", { guildId, requestId }) logger.info("Sending vote closed message.", { guildId, requestId })
if(!announcementChannel) { if (!announcementChannel) {
logger.error("Could not find announcement channel. Please fix!", { guildId, requestId }) logger.error("Could not find announcement channel. Please fix!", { guildId, requestId })
return return
} }
@ -146,3 +146,39 @@ function extractMovieFromMessageByEmote(message: Message, emote: string): string
return movie return movie
} }
export async function checkForPollsToClose(guild: Guild): Promise<void> {
const requestId = uuid()
logger.info(`Automatic check for poll closing.`, { guildId: guild.id, requestId })
const events = (await guild.scheduledEvents.fetch()).filter(event => event.name.toLocaleLowerCase().includes("voting offen")).map(event => event)
if (events.length > 1) {
logger.error("Handling more than one Event is not implemented yet. Found more than one poll to close")
return
} else if (events.length == 0) {
logger.info("Could not find any events. Cancelling", { guildId: guild.id, requestId })
}
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: guild.id, requestId })
return
}
const createDate: Date = toDate(updatedEvent.createdTimestamp)
const eventDate: Date = toDate(updatedEvent.scheduledStartTimestamp)
const difference: number = differenceInDays(createDate, eventDate)
if (difference <= 2) {
logger.info("Less than two days between event create and event start. Not closing poll.", { guildId: guild.id, requestId })
return
}
const closePollDate: Date = addDays(eventDate, -2)
if (isAfter(Date.now(), closePollDate)) {
logger.info("Less than two days until event. Closing poll", { guildId: guild.id, requestId })
closePoll(guild, requestId)
} else {
logger.info(`ScheduledStart: ${closePollDate}. Now: ${toDate(Date.now())}`, { guildId: guild.id, requestId })
}
}

View File

@ -5,7 +5,7 @@ import { accountChoice, joingroup, leavegroup, loginScreen, overview, resume, se
import { logger } from '../logger' import { logger } from '../logger'
import { Command } from '../structures/command' import { Command } from '../structures/command'
import { RunOptions } from '../types/commandTypes' import { RunOptions } from '../types/commandTypes'
import { configureServer, explainRoles, installation, loginInfo, useSyncgroup } from './mitgucken' import { configureServer, explainRole, installation, loginInfo, useSyncgroup } from './mitgucken'
export default new Command({ export default new Command({
name: 'guides', name: 'guides',
@ -70,7 +70,7 @@ export default new Command({
userDMChannel.send({ embeds: useSyncgroup(), files: [overview, joingroup, resume, leavegroup] }) userDMChannel.send({ embeds: useSyncgroup(), files: [overview, joingroup, resume, leavegroup] })
} else if (guideSelection.customId === 'explainRoles') { } else if (guideSelection.customId === 'explainRoles') {
const userDMChannel = await guideSelection.user.createDM() const userDMChannel = await guideSelection.user.createDM()
userDMChannel.send(explainRoles()) userDMChannel.send({ embeds: explainRole() })
} }
guideSelection.update({ content: "Hab ich dir per DM geschickt :)", components: [] }) guideSelection.update({ content: "Hab ich dir per DM geschickt :)", components: [] })

View File

@ -16,13 +16,9 @@ export default new Command({
const embedList: APIEmbed[] = [] const embedList: APIEmbed[] = []
embedList.push(...installation()) embedList.push(...installation())
embedList.push(...configureServer()) embedList.push(...configureServer())
embedList.push(...explainRole())
embedList.push(...loginInfo()) embedList.push(...loginInfo())
embedList.push(...useSyncgroup()) embedList.push(...useSyncgroup())
embedList.push({
color,
title: "Wie du an einen Account kommst",
description: explainRoles()
})
//logger.info(`Trying to use ${splashScreen.name}`, { requestId, guildId: interaction.interaction.guild?.id }) //logger.info(`Trying to use ${splashScreen.name}`, { requestId, guildId: interaction.interaction.guild?.id })
logger.info(`Sending guide to ${interaction.interaction.user.id}`, { requestId, guildId: interaction.interaction.guild?.id }) logger.info(`Sending guide to ${interaction.interaction.user.id}`, { requestId, guildId: interaction.interaction.guild?.id })
@ -32,6 +28,13 @@ export default new Command({
}) })
export function explainRole(): APIEmbed[] {
return [{
color,
title: "Wie du an einen Account kommst",
description: roleExplanation
}]
}
export function installation(): APIEmbed[] { export function installation(): APIEmbed[] {
const embedList: APIEmbed[] = [] const embedList: APIEmbed[] = []
// DownloadLink and installation // DownloadLink and installation
@ -67,7 +70,7 @@ export function configureServer(): APIEmbed[] {
title: "Server Verbindung", title: "Server Verbindung",
description: "Stelle eine Verbindung zum Hartzarett Jellyfin Server her", description: "Stelle eine Verbindung zum Hartzarett Jellyfin Server her",
fields: [ fields: [
{ name: "Server Adresse", value: "https://media.hartzarett.ruhr" } { name: "Server Adresse", value: "`https://media.hartzarett.ruhr`" }
], ],
image: { image: {
url: 'attachment://server_verbindung.png' url: 'attachment://server_verbindung.png'
@ -91,7 +94,7 @@ export function loginInfo(): APIEmbed[] {
embedList.push({ embedList.push({
color, color,
title: "Login", title: "Login",
description: "Melde dich mit dem Usernamen und Passwort an, welches dir von mir zugeschickt wird. Falls du ein neues brauchst führe einmal /reset_passwort aus :)", description: "Melde dich mit dem Usernamen und Passwort an, welches dir von mir zugeschickt wird. Falls du ein neues brauchst führe einmal `/passwort_reset` aus :)",
image: { image: {
url: 'attachment://login_screen.png' url: 'attachment://login_screen.png'
} }
@ -139,8 +142,7 @@ export function useSyncgroup(): APIEmbed[] {
return embedList return embedList
} }
export function explainRoles(): string { const roleExplanation = `Mit einer Rolle kann dafür gesorgt werden, dass du einen dauerhaften Account auf dem Mediaserver hast. Wende dich bei Bedarf an Samantha oder Markus.\n
return `Mit einer Rolle kann dafür gesorgt werden, dass du einen dauerhaften Account auf dem Mediaserver hast. Wende dich bei Bedarf an Samantha oder Markus.\n
Für eine watchparty bekommst du allerdings automatisch einen Account. Hierfür melde einfach Interesse an dem Event an. Wenn du für das Event Interesse angemeldet hast bekommst du automatisch beim Start des Events einen Benutzernamen und das dazugehörige Passwort zugesendet.\n Für eine watchparty bekommst du allerdings automatisch einen Account. Hierfür melde einfach Interesse an dem Event an. Wenn du für das Event Interesse angemeldet hast bekommst du automatisch beim Start des Events einen Benutzernamen und das dazugehörige Passwort zugesendet.\n
Hast du kein Interesse angemeldet bekommst du automatisch einen Nutzernamen und Passwort zugeschickt wenn du den Channel betrittst in dem das Event stattfindet.` Hast du kein Interesse angemeldet bekommst du automatisch einen Nutzernamen und Passwort zugeschickt wenn du den Channel betrittst in dem das Event stattfindet.`
}

View File

@ -1,10 +1,8 @@
import { addDays, format, isAfter } from "date-fns"; import { format } from "date-fns";
import toDate from "date-fns/fp/toDate";
import { GuildScheduledEvent, Message, MessageCreateOptions, TextChannel } from "discord.js"; import { GuildScheduledEvent, Message, MessageCreateOptions, TextChannel } from "discord.js";
import { ScheduledTask, schedule } from "node-cron"; import { ScheduledTask } from "node-cron";
import { v4 as uuid } from "uuid"; import { v4 as uuid } from "uuid";
import { client, yavinJellyfinHandler } from "../.."; import { client, yavinJellyfinHandler } from "../..";
import { closePoll } from "../commands/closepoll";
import { config } from "../configuration"; import { config } from "../configuration";
import { Maybe } from "../interfaces"; import { Maybe } from "../interfaces";
import { logger } from "../logger"; import { logger } from "../logger";
@ -24,10 +22,10 @@ export async function execute(event: GuildScheduledEvent) {
logger.info("Event was a placeholder event to start a new watchparty and voting. Creating vote!", { guildId: event.guildId, requestId }) 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 }) logger.debug("Renaming event", { guildId: event.guildId, requestId })
event.edit({ name: "Watchparty - Voting offen" }) event.edit({ name: "Watchparty - Voting offen" })
const movies = await yavinJellyfinHandler.getRandomMovies(5, event.guildId, requestId) const movies = await yavinJellyfinHandler.getRandomMovieNames(5, event.guildId, requestId)
logger.info(`Got ${movies.length} random movies. Creating voting`, { guildId: 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 }) logger.debug(`Movies: ${JSON.stringify(movies)}`, { guildId: event.guildId, requestId })
const announcementChannel: Maybe<TextChannel> = client.getAnnouncementChannelForGuild(event.guildId) const announcementChannel: Maybe<TextChannel> = client.getAnnouncementChannelForGuild(event.guildId)
if(!announcementChannel) { if(!announcementChannel) {
@ -45,7 +43,7 @@ export async function execute(event: GuildScheduledEvent) {
let message = `[Abstimmung]\n<@&${config.bot.announcement_role}> Es gibt eine neue Abstimmung für die nächste Watchparty am ${date} um ${time}}! Stimme hierunter für den nächsten Film ab!\n` let message = `[Abstimmung]\n<@&${config.bot.announcement_role}> Es gibt eine neue Abstimmung für die nächste Watchparty am ${date} um ${time}}! Stimme hierunter für den nächsten Film ab!\n`
for (let i = 0; i < movies.length; i++) { for (let i = 0; i < movies.length; i++) {
message = message.concat(Emotes[i]).concat(": ").concat(movies[i].name ?? "Film hatte keinen Namen :(").concat("\n") message = message.concat(Emotes[i]).concat(": ").concat(movies[i]).concat("\n")
} }
const options: MessageCreateOptions = { const options: MessageCreateOptions = {
@ -59,46 +57,7 @@ export async function execute(event: GuildScheduledEvent) {
sentMessage.react(Emotes[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 // 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<void> {
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 })
}
}

View File

@ -28,6 +28,7 @@ export async function execute(oldEvent: GuildScheduledEvent, newEvent: GuildSche
members.push(member) members.push(member)
} }
if (newEvent.status === GuildScheduledEventStatus.Active) if (newEvent.status === GuildScheduledEventStatus.Active)
createJFUsers(members, newEvent.name, requestId) createJFUsers(members, newEvent.name, requestId)
else { else {

View File

@ -242,10 +242,21 @@ export class JellyfinHandler {
const index = Math.floor(Math.random() * allMovies.length) const index = Math.floor(Math.random() * allMovies.length)
movies.push(...allMovies.splice(index, 1)) // maybe out of bounds? ? movies.push(...allMovies.splice(index, 1)) // maybe out of bounds? ?
} }
return movies return movies
} }
public async getRandomMovieNames(count: number, guildId: string, requestId: string): Promise<string[]> {
logger.info(`${count} random movie names requested`, { guildId, requestId })
let movieCount = 0
let movieNames: string[]
do {
movieNames = (await this.getRandomMovies(count, guildId, requestId)).filter(movie => movie.name && movie.name.length > 0).map(movie => <string> movie.name)
movieCount = movieNames.length
} while (movieCount < count)
return movieNames
}
} }
export enum UserUpsertResult { enabled, created } export enum UserUpsertResult { enabled, created }

View File

@ -8,6 +8,7 @@ import { Maybe } from "../interfaces";
import { JellyfinHandler } from "../jellyfin/handler"; import { JellyfinHandler } from "../jellyfin/handler";
import { logger } from "../logger"; import { logger } from "../logger";
import { CommandType } from "../types/commandTypes"; import { CommandType } from "../types/commandTypes";
import { checkForPollsToClose } from "../commands/closepoll";
@ -16,8 +17,9 @@ export class ExtendedClient extends Client {
private commandFilePath = `${__dirname}/../commands` private commandFilePath = `${__dirname}/../commands`
private jellyfin: JellyfinHandler private jellyfin: JellyfinHandler
public commands: Collection<string, CommandType> = new Collection() public commands: Collection<string, CommandType> = new Collection()
private announcementChannels: Collection<string, TextChannel> = new Collection //guildId to TextChannel private announcementChannels: Collection<string, TextChannel> = new Collection() //guildId to TextChannel
private announcementRoleHandlerTask: Collection<string, ScheduledTask> = new Collection //one task per guild private announcementRoleHandlerTask: Collection<string, ScheduledTask> = new Collection() //one task per guild
private pollCloseBackgroundTasks: Collection<string, ScheduledTask> = new Collection()
public constructor(jf: JellyfinHandler) { public constructor(jf: JellyfinHandler) {
const intents: IntentsBitField = new IntentsBitField() const intents: IntentsBitField = new IntentsBitField()
intents.add(IntentsBitField.Flags.GuildMembers, IntentsBitField.Flags.MessageContent, IntentsBitField.Flags.Guilds, IntentsBitField.Flags.DirectMessages, IntentsBitField.Flags.GuildScheduledEvents, IntentsBitField.Flags.GuildVoiceStates) intents.add(IntentsBitField.Flags.GuildMembers, IntentsBitField.Flags.MessageContent, IntentsBitField.Flags.Guilds, IntentsBitField.Flags.DirectMessages, IntentsBitField.Flags.GuildScheduledEvents, IntentsBitField.Flags.GuildVoiceStates)
@ -73,6 +75,7 @@ export class ExtendedClient extends Client {
this.cacheUsers(guilds) this.cacheUsers(guilds)
await this.cacheAnnouncementServer(guilds) await this.cacheAnnouncementServer(guilds)
this.startAnnouncementRoleBackgroundTask(guilds) this.startAnnouncementRoleBackgroundTask(guilds)
this.startPollCloseBackgroundTasks()
}) })
} catch (error) { } catch (error) {
logger.info(`Error refreshing slash commands: ${error}`) logger.info(`Error refreshing slash commands: ${error}`)
@ -169,4 +172,10 @@ export class ExtendedClient extends Client {
} }
task.stop() task.stop()
} }
private async startPollCloseBackgroundTasks() {
for(const guild of this.guilds.cache) {
this.pollCloseBackgroundTasks.set(guild[1].id, schedule("0 * * * * *", () => checkForPollsToClose(guild[1])))
}
}
} }