Skip to content
This repository was archived by the owner on Feb 3, 2026. It is now read-only.

Commit c595b65

Browse files
author
BuildTools
committed
- meal plan feature (see readme)
1 parent bdb3f30 commit c595b65

File tree

7 files changed

+3265
-16
lines changed

7 files changed

+3265
-16
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,8 @@ typings/
6363
# next.js build output
6464
.next
6565
*.sqlite
66+
mealplan.pdf
67+
.gitignore
68+
.vscode/launch.json
69+
untitled.1.png
70+
mensaplan.1.png

README.md

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ In order for the bot to communicate with channels, you need to edit the `general
2929

3030
### Roles
3131

32-
staffrole: this is the management role, which may edit the bot via commands.
33-
verified: after a playeer verified with his account. Use this role as you please, maybe to show and hide some channels.
32+
- staffrole: this is the management role, which may edit the bot via commands.
33+
- verified: after a playeer verified with his account. Use this role as you please, maybe to show and hide some channels.
34+
- mealplannotify: role id which will get pinged if new mealplan has been posted
3435

3536
### Channels
3637

@@ -40,6 +41,8 @@ verified: after a playeer verified with his account. Use this role as you please
4041
- xp : where level ups get posted
4142
- rules : where your server rules are located
4243
- ads: where external members may post ads which automatically get deleted after a specified amout of time in the settings
44+
- createChannel: when creating a voice channel with this name, it will be a dynamic voice channel to prevent unnecessary voice channels
45+
- mealPlan: channel to which the mealplan updates get posted
4346

4447
### Colors
4548

@@ -50,6 +53,21 @@ Speficy the color codes which gets used by the bot when sending embedded mssages
5053
Here you may speficy other adjustable settings of the bot.
5154
- adstimeout: the time in milliseconds before an ad in the ads-channel gets deleted
5255
- CharsForLevel: how many characters in a message should equal to 1 Point of Experience
56+
- postMealplan: (bool) activates the mealplan posting functionality
57+
- mealplan : (url) place to download mealplan i.e. http://www.meal/one.pdf
58+
- mealplanpdfpath": (path) local path to save and load mealplan
59+
- mealplan-check": (int) minutes between the mealplan update check
60+
- mealplandaycheck": (int) weekday on which the check and post occurs (0 - 6) (Sun - Sat)
61+
- mealplanhourscheck: (int) time at what the check occurs. i.e. 8 for 8am
62+
- mealplansettings": (list) default settings for the converter. change if applicable
63+
- density": 400,
64+
- quality": 100,
65+
- saveFilename": "mensaplan",
66+
- savePath": "./",
67+
- format": "png",
68+
- width": 768,
69+
- height": 512
70+
}
5371

5472
### Other
5573

functions/extensions.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
const settings = require("../general-settings.json");
2+
const fs = require('fs');
3+
const http = require('http');
4+
const https = require('https');
5+
26
// xp calculation
37
module.exports = {
48
toLevel(number) {
@@ -26,4 +30,44 @@ module.exports = {
2630
).send(msg);
2731
console.log(msg);
2832
},
33+
34+
/**
35+
* Downloads file from remote HTTP[S] host and puts its contents to the
36+
* specified location.
37+
*/
38+
async download(url, filePath) {
39+
const proto = !url.charAt(4).localeCompare('s') ? https : http;
40+
41+
return new Promise((resolve, reject) => {
42+
const file = fs.createWriteStream(filePath);
43+
let fileInfo = null;
44+
45+
const request = proto.get(url, response => {
46+
if (response.statusCode !== 200) {
47+
reject(new Error(`Failed to get '${url}' (${response.statusCode})`));
48+
return;
49+
}
50+
51+
fileInfo = {
52+
mime: response.headers['content-type'],
53+
size: parseInt(response.headers['content-length'], 10),
54+
};
55+
56+
response.pipe(file);
57+
});
58+
59+
// The destination stream is ended by the time it's called
60+
file.on('finish', () => resolve(fileInfo));
61+
62+
request.on('error', err => {
63+
fs.unlink(filePath, () => reject(err));
64+
});
65+
66+
file.on('error', err => {
67+
fs.unlink(filePath, () => reject(err));
68+
});
69+
70+
request.end();
71+
});
72+
}
2973
};

general-settings.json

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"news": "ankündigungen",
66
"logs": "logs",
77
"ads": "stellenausschreibungen",
8-
"createChannel": "🔊 Neuer Voicechannel"
8+
"createChannel": "🔊 Neuer Voicechannel",
9+
"mealPlan": "899606239804268545"
910
},
1011
"colors": {
1112
"blue": "#4200ff",
@@ -15,10 +16,26 @@
1516
},
1617
"roles": {
1718
"staffrole": "Admin",
18-
"verified": "Student"
19+
"verified": "Student",
20+
"mealplannotify": "899619452897882142"
1921
},
2022
"settings": {
2123
"adstimeout": 2147483647,
22-
"CharsForLevel": 200
24+
"CharsForLevel": 200,
25+
"postMealplan": true,
26+
"mealplan": "http://www.max-manager.de/daten-extern/augsburg/pdf/wochenplaene/hs-kempten/aktuell.pdf",
27+
"mealplanpdfpath": "/home/akgaming/discord/faculty/usability-bot/mealplan.pdf",
28+
"mealplan-check": 1,
29+
"mealplandaycheck": 1,
30+
"mealplanhourscheck": 8,
31+
"mealplansettings":{
32+
"density": 400,
33+
"quality": 100,
34+
"saveFilename": "mensaplan",
35+
"savePath": "./",
36+
"format": "png",
37+
"width": 768,
38+
"height": 512
39+
}
2340
}
2441
}

index.js

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@ const Keyv = require("keyv");
66
const sqlite3 = require("sqlite3").verbose();
77
const { prefix, token, mailpw } = require("./config.json");
88
const MailPw = mailpw; // prevent on demand loading
9-
const { toLevel, logMessage } = require("./functions/extensions.js");
9+
const { toLevel, logMessage, downloadURI, download } = require("./functions/extensions.js");
1010
const settings = require("./general-settings.json");
1111
const fs = require("fs");
12+
1213
inspect = require("util").inspect;
14+
const pdf2image = require('pdf2image')
15+
const { fromPath } = require("pdf2pic");
1316

1417
const bot = new Discord.Client();
1518

@@ -54,6 +57,52 @@ bot.login(token);
5457
bot.on("ready", () => {
5558
console.info(`Logged in as ${bot.user.tag}!`);
5659
bot.user.setActivity("use ..help", { type: "PLAYING" });
60+
61+
// const options = {
62+
// density: 400,
63+
// quality: 100,
64+
// saveFilename: "mensaplan",
65+
// savePath: "./",
66+
// format: "png",
67+
// width: 768,
68+
// height: 512
69+
// };
70+
71+
// mealplan check
72+
var minutes = settings.settings["mealplan-check"], meal_check_interval = minutes * 60 * 1000;
73+
// if feature is activated
74+
if (settings.settings.postMealplan)
75+
setInterval(async function () {
76+
isWeekdayNow = new Date().getDay() == settings.settings.mealplandaycheck ? 1 : 0
77+
if (isWeekdayNow) {
78+
// if after x hours on the new day
79+
if (new Date().getHours() >= settings.settings.mealplanhourscheck) {
80+
let channel = bot.channels.cache.get(settings.channels.mealPlan)
81+
// check if already posted today
82+
// if not been posted today
83+
channel.messages.fetch({ limit: 1 }).then(messages => async function () {
84+
let lastMessage = messages.first();
85+
if (new Date(lastMessage.createdTimestamp).getDate() != new Date().getDate()) {
86+
if (channel != undefined) {
87+
await download(settings.settings.mealplan, settings.settings.mealplanpdfpath)
88+
console.log("Mensaplan downloaded");
89+
// ConvertedFile
90+
const storeAsImage = fromPath(settings.settings.mealplanpdfpath, settings.settings.mealplansettings);
91+
const pageToConvertAsImage = 1;
92+
93+
storeAsImage(pageToConvertAsImage).then((resolve) => {
94+
console.log("Mensaplan converted");
95+
96+
channel.send(`<@&${settings.roles.mealplannotify}>`, { files: [resolve.path] });
97+
return resolve;
98+
});
99+
100+
}
101+
}
102+
}).catch(console.error);
103+
}
104+
}
105+
}, meal_check_interval);
57106
});
58107
//--------------------------------------------------
59108
// MESSAGE
@@ -71,6 +120,8 @@ bot.on("message", async (message) => {
71120
logMessage(message, error);
72121
}
73122
}
123+
124+
74125
if (!message.content.startsWith(prefix) && message.channel.type == "text") {
75126
// handle ads
76127
if (message.channel.name == settings.channels.ads) {
@@ -83,6 +134,7 @@ bot.on("message", async (message) => {
83134
message.delete({ timeout: settings.settings.adstimeout }); // 4 weeks
84135
}
85136

137+
86138
const userXP = await dbxp.get(message.author.id);
87139

88140
// user xp
@@ -145,7 +197,7 @@ bot.on("message", async (message) => {
145197
dbxp.set(
146198
message.author.id,
147199
userXP +
148-
message.content.length / parseFloat(settings.settings.CharsForLevel)
200+
message.content.length / parseFloat(settings.settings.CharsForLevel)
149201
);
150202
}
151203

@@ -195,8 +247,7 @@ bot.on("message", async (message) => {
195247
if (now < expirationTime) {
196248
const timeLeft = (expirationTime - now) / 1000;
197249
return message.reply(
198-
`please wait ${timeLeft.toFixed(1).toHHMMSS()} before reusing the \`${
199-
command.name
250+
`please wait ${timeLeft.toFixed(1).toHHMMSS()} before reusing the \`${command.name
200251
}\` command.`
201252
);
202253
}

0 commit comments

Comments
 (0)