feat: implement Ancestor quote bot with Docker support
This commit is contained in:
5
.dockerignore
Normal file
5
.dockerignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
.git
|
||||||
|
node_modules
|
||||||
|
.env
|
||||||
|
node/
|
||||||
|
.npm
|
||||||
5
.env.example
Normal file
5
.env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# Matrix Ancestor Quote Bot Configuration
|
||||||
|
|
||||||
|
MATRIX_HOME_SERVER=https://your.matrix.server.com:443
|
||||||
|
MATRIX_ACCESS_TOKEN=your_access_token_here
|
||||||
|
BOT_COMMAND=!quote
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
.env
|
||||||
|
.git
|
||||||
|
*.log
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
FROM node:18-alpine
|
FROM node:18-alpine
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
RUN npm install --production
|
RUN npm install
|
||||||
COPY . .
|
COPY . .
|
||||||
|
RUN npm prune --production
|
||||||
CMD ["node", "index.js"]
|
CMD ["node", "index.js"]
|
||||||
41
README.md
41
README.md
@@ -1,3 +1,40 @@
|
|||||||
# matrix-quotes-bot
|
# Ancestor Quote Bot
|
||||||
|
|
||||||
AKA ancestor bot. By default it just quotes the Ancestor from Darkest Dungeons. It's like 25 lines of JS and some libraries.
|
A Matrix chatbot that responds to `/quote` commands with random quotes from Darkest Dungeons' Narrator/Ancestor.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
1. Copy `.env.example` to `.env` and fill in your credentials:
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Build the Docker image:
|
||||||
|
```bash
|
||||||
|
docker build -t ancestor-quote-bot .
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Run the bot:
|
||||||
|
```bash
|
||||||
|
docker run --rm \
|
||||||
|
-e MATRIX_HOME_SERVER=https://your.matrix.server.com \
|
||||||
|
-e MATRIX_ACCESS_TOKEN=your_access_token_here \
|
||||||
|
ancestor-quote-bot
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
- `MATRIX_HOME_SERVER`: Your Matrix homeserver URL (e.g., https://matrix.org)
|
||||||
|
- `MATRIX_ACCESS_TOKEN`: Bot access token for authentication
|
||||||
|
- `BOT_COMMAND`: The command trigger (default: `!quote`)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Type the bot command in any room you've joined, and it will reply with a random Ancestor quote.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
Room: #general:matrix.org
|
||||||
|
!quote
|
||||||
|
Bot: Dispatch this thug in brutal fashion, that all may hear of your arrival!
|
||||||
|
```
|
||||||
|
|||||||
9
docker-compose.yml
Normal file
9
docker-compose.yml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
services:
|
||||||
|
ancestor-bot:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
environment:
|
||||||
|
- MATRIX_HOME_SERVER=${MATRIX_HOME_SERVER:-https://matrix.org}
|
||||||
|
- MATRIX_ACCESS_TOKEN=${MATRIX_ACCESS_TOKEN:?required}
|
||||||
|
- BOT_COMMAND=${BOT_COMMAND:-!quote}
|
||||||
52
index.js
52
index.js
@@ -4,21 +4,63 @@ const fs = require('fs');
|
|||||||
|
|
||||||
const client = new Client({
|
const client = new Client({
|
||||||
accessToken: process.env.MATRIX_ACCESS_TOKEN,
|
accessToken: process.env.MATRIX_ACCESS_TOKEN,
|
||||||
ejmtls: process.env.MATRIX_EJMTLS || undefined,
|
|
||||||
matrix_homeserver: {
|
matrix_homeserver: {
|
||||||
baseUrl: process.env.MATRIX_HOME_SERVER,
|
baseUrl: process.env.MATRIX_HOME_SERVER,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const quotes = JSON.parse(fs.readFileSync('./quotes.json', 'utf8'));
|
async function loadQuotes() {
|
||||||
|
const quotesFile = './quotes.json';
|
||||||
|
if (fs.existsSync(quotesFile)) {
|
||||||
|
return JSON.parse(fs.readFileSync(quotesFile, 'utf8'));
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
client.on('sysjmn_message', (event) => {
|
const quotes = await loadQuotes();
|
||||||
if (event.content && event.content.includes(process.env.BOT_COMMAND)) {
|
|
||||||
|
if (quotes.length === 0) {
|
||||||
|
console.error('No quotes found! Please ensure quotes.json is present.');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let joinedRooms = new Set();
|
||||||
|
|
||||||
|
client.on('RoomMember#joined', (member) => {
|
||||||
|
const room = member.room;
|
||||||
|
if (!joinedRooms.has(room.roomId)) {
|
||||||
|
joinedRooms.add(room.roomId);
|
||||||
|
console.log(`Joined room: ${room.roomId}`);
|
||||||
|
|
||||||
|
room.on('EventMessage', async (event) => {
|
||||||
|
const messageContent = event.getContent();
|
||||||
|
|
||||||
|
if (!messageContent || !messageContent.body) return;
|
||||||
|
|
||||||
|
const body = messageContent.body.toLowerCase();
|
||||||
|
const botCommand = (process.env.BOT_COMMAND || '!quote').toLowerCase();
|
||||||
|
|
||||||
|
if (body.includes(botCommand)) {
|
||||||
const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
|
const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
|
||||||
client.sendMessage(event.roomId, randomQuote);
|
try {
|
||||||
|
await room.sendMessage(randomQuote);
|
||||||
|
console.log(`Sent quote to ${room.roomId}`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to send message:', err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
room.on('RoomMember#left', () => {
|
||||||
|
joinedRooms.delete(room.roomId);
|
||||||
|
console.log(`Left room: ${room.roomId}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.init().then(() => {
|
client.init().then(() => {
|
||||||
console.log('Bot is online');
|
console.log('Bot is online');
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Failed to initialize client:', err.message);
|
||||||
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user