diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..75604e6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +.git +node_modules +.env +node/ +.npm \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..9057a62 --- /dev/null +++ b/.env.example @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7652d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.env +.git +*.log diff --git a/Dockerfile b/Dockerfile index 35a3e39..1fa0df2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,7 @@ FROM node:18-alpine WORKDIR /app COPY package*.json ./ -RUN npm install --production +RUN npm install COPY . . +RUN npm prune --production CMD ["node", "index.js"] \ No newline at end of file diff --git a/README.md b/README.md index 5f54879..8aa7abd 100644 --- a/README.md +++ b/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. \ No newline at end of file +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! +``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..37b80b1 --- /dev/null +++ b/docker-compose.yml @@ -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} diff --git a/index.js b/index.js index 7f5d423..edbdf5e 100644 --- a/index.js +++ b/index.js @@ -4,21 +4,63 @@ const fs = require('fs'); const client = new Client({ accessToken: process.env.MATRIX_ACCESS_TOKEN, - ejmtls: process.env.MATRIX_EJMTLS || undefined, matrix_homeserver: { 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) => { - if (event.content && event.content.includes(process.env.BOT_COMMAND)) { - const randomQuote = quotes[Math.floor(Math.random() * quotes.length)]; - client.sendMessage(event.roomId, randomQuote); +const quotes = await loadQuotes(); + +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)]; + 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(() => { console.log('Bot is online'); +}).catch(err => { + console.error('Failed to initialize client:', err.message); + process.exit(1); });