diff options
Diffstat (limited to 'bot')
| -rwxr-xr-x | bot/bun.lockb | bin | 0 -> 11472 bytes | |||
| -rw-r--r-- | bot/index.ts | 106 | ||||
| -rw-r--r-- | bot/package.json | 13 | ||||
| -rw-r--r-- | bot/tsconfig.json | 12 |
4 files changed, 131 insertions, 0 deletions
diff --git a/bot/bun.lockb b/bot/bun.lockb Binary files differnew file mode 100755 index 0000000..28b13e5 --- /dev/null +++ b/bot/bun.lockb diff --git a/bot/index.ts b/bot/index.ts new file mode 100644 index 0000000..e3a2c6a --- /dev/null +++ b/bot/index.ts @@ -0,0 +1,106 @@ +import { Client, Events, GatewayIntentBits } from 'discord.js'; +import { Database } from "bun:sqlite"; + +const client = new Client({ intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, GatewayIntentBits.GuildMessages, GatewayIntentBits.MessageContent] }); +const db = new Database("../database.sqlite", { create: true }); + +function parseMessage(content: string) { + const lines = content.split('\n'); + const authorMatch = content.match(/\*from(?: the)? ([^*]+)\*/i); + const titleLine = lines.slice(0, 2).find(l => /^#+\s+.+|^.+\*\*[^*]+\*\*$/.test(l)) ?? null; + + const author = authorMatch ? authorMatch[1].trim() : null; + const title = titleLine ? titleLine.replace(/^#+\s+/, '').replace(/\*\*/g, '').trim() : null; + const message = lines + .filter(l => l !== titleLine) + .join('\n') + .replace(/\*from(?: the)? [^*]+\*\n?/i, '') + .trimStart(); + + return { author, title, message }; +} + +client.on(Events.ClientReady, bot => { + console.log(`Logged in as ${bot.user.tag}!`); + client.user?.setStatus('invisible'); + + try { + db.run(`CREATE TABLE IF NOT EXISTS announcements ( + id INTEGER PRIMARY KEY, + msg_id INTERGER, + title TEXT, + author TEXT, + message TEXT, + created_at INTEGER + )`); + } catch (e) { + console.error(e); + } +}); + +client.on(Events.MessageCreate, async (msg) => { + if (msg.author.bot) return; + if (msg.author.id === client.user!.id) return; + if (msg.channel.id !== process.env.ANNOUNCEMENT_CHANNEL) return; + if (!(msg.content.startsWith('# ') || msg.content.startsWith('*') || msg.content.match(/^:[a-z0-9_]+:/i) || msg.content.match(/^\p{Emoji}/u))) return; + + const { title, author, message } = parseMessage(msg.content); + + try { + const insert = db.prepare(`INSERT INTO announcements (title, msg_id, author, message, created_at) VALUES (($title), ($msg_id), ($author), ($message), ($created_at))`); + insert.run({ + $title: title, + $msg_id: msg.id, + $author: author, + $message: message, + $created_at: msg.createdTimestamp.toString() + }) + } catch (e) { + console.error(e); + } + +}); + +client.on(Events.MessageUpdate, async (msg, msgnew) => { + if (!msg.author) return; + if (!msg.content) return; + if (msg.author.bot) return; + if (msg.author.id === client.user!.id) return; + if (msg.channel.id !== process.env.ANNOUNCEMENT_CHANNEL) return; + if (!(msgnew.content.startsWith('# ') || msgnew.content.startsWith('*') || msgnew.content.match(/^:[a-z0-9_]+:/i) || msgnew.content.match(/^\p{Emoji}/u))) return; + + const { title, author, message } = parseMessage(msgnew.content); + + try { + const update = db.prepare(`UPDATE announcements SET title = ($title), author = ($author), message = ($message) WHERE msg_id = ($msg_id)`); + update.run({ + $title: title, + $author: author, + $message: message, + $msg_id: msg.id + }) + } catch (e) { + console.error(e); + } + +}); + +client.on(Events.MessageDelete, async (msg) => { + if (!msg.author) return; + if (!msg.content) return; + if (msg.author.bot) return; + if (msg.author.id === client.user!.id) return; + if (msg.channel.id !== process.env.ANNOUNCEMENT_CHANNEL) return; + + try { + const deleteAnnouncement = db.prepare(`DELETE FROM announcements WHERE msg_id = ($msg_id)`); + deleteAnnouncement.run({ + $msg_id: msg.id + }) + } catch (e) { + console.error(e); + } + +}); + +client.login(process.env.TOKEN); diff --git a/bot/package.json b/bot/package.json new file mode 100644 index 0000000..4ada057 --- /dev/null +++ b/bot/package.json @@ -0,0 +1,13 @@ +{ + "name": "bot", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "discord.js": "^14.26.2" + }, + "devDependencies": { + "@types/bun": "^1.3.11", + "@types/node": "^25.5.2" + } +} diff --git a/bot/tsconfig.json b/bot/tsconfig.json new file mode 100644 index 0000000..f737fec --- /dev/null +++ b/bot/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "module": "NodeNext", /* Specify what module code is generated. */ + "moduleResolution": "NodeNext", + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + "strict": true, /* Enable all strict type-checking options. */ + "skipLibCheck": true, /* Skip type checking all .d.ts files. */ + "types": ["node", "bun"] + } +} |
