Files
matrix-quotes-bot/index.js

136 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import * as dotenv from 'dotenv';
import { MatrixClient } from 'matrix-js-sdk';
import fs from 'fs';
dotenv.config();
console.log('🚀 Starting Ancestor Quote Bot...\n');
const client = new MatrixClient({
accessToken: process.env.MATRIX_ACCESS_TOKEN,
baseUrl: process.env.MATRIX_HOME_SERVER,
});
function loadQuotes() {
try {
const quotesFile = './quotes.json';
if (fs.existsSync(quotesFile)) {
return JSON.parse(fs.readFileSync(quotesFile, 'utf8'));
}
} catch (err) {
console.error('Error loading quotes:', err.message);
}
return [];
}
(async () => {
const quotes = loadQuotes();
if (quotes.length === 0) {
console.error('❌ No quotes found! Please ensure quotes.json is present.');
process.exit(1);
}
console.log(`✅ Loaded ${quotes.length} Ancestor quotes`);
// Validate environment variables first
const token = process.env.MATRIX_ACCESS_TOKEN;
const server = process.env.MATRIX_HOME_SERVER;
if (!token || !server) {
console.error('❌ Missing required environment variables!');
console.error(' Required: MATRIX_ACCESS_TOKEN, MATRIX_HOME_SERVER');
console.error(' See .env.example for guidance.');
process.exit(1);
}
console.log(`🏠 Server: ${server}`);
try {
await client.startClient();
console.log('✅ MatrixClient connected and authenticated\n');
let lastSentMessage = null;
// Listen for all membership events from homeserver
client.on('RoomMember#joined', async (member) => {
const room = member.room;
console.log(`✅ Joined room: ${room.getCanonicalRoomName() || room.roomId}`);
// Add message listener to this room
room.on('EventMessage', async (event, stateEvent) => {
const content = event.getContent();
if (!content || !content.body) return;
const body = content.body.toLowerCase().trim();
const cmd = (process.env.BOT_COMMAND || '!quote').toLowerCase();
if (body === cmd || body.startsWith(cmd)) {
if (!lastSentMessage || Date.now() - lastSentMessage > 300) {
const quote = quotes[Math.floor(Math.random() * quotes.length)];
try {
await room.sendMessage(quote);
console.log(`🎃 Quote: ${quote}`);
lastSentMessage = Date.now();
} catch (err) {
console.error('Failed to send quote:', err.message);
}
}
}
});
// Handle leaving the room
member.room.on('RoomMember#left', () => {
console.log(`ℹ️ Left room: ${member.room.getCanonicalRoomName() || member.room.roomId}`);
});
});
// Also listen to messages from all known rooms (for cases where client is already joined)
client.on('EventMessage', async (event, stateEvent) => {
const room = event.sender.room;
const content = event.getContent();
if (!content || !content.body) return;
const body = content.body.toLowerCase().trim();
const cmd = (process.env.BOT_COMMAND || '!quote').toLowerCase();
// Only respond in rooms where we're a member
const roomMembers = await room.getJoinedMemberCount();
if (roomMembers > 0 && room.getMyMembership()) {
if (body === cmd || body.startsWith(cmd)) {
if (!lastSentMessage || Date.now() - lastSentMessage > 300) {
const quote = quotes[Math.floor(Math.random() * quotes.length)];
try {
await room.sendMessage(quote);
console.log(`🎃 Quote: ${quote}`);
lastSentMessage = Date.now();
} catch (err) {
console.error('Failed to send quote:', err.message);
}
}
}
}
});
console.log('🤖 Bot is running!');
console.log(' Invite this bot to a Matrix room and type to get an Ancestor quote.\n');
} catch (err) {
console.error('Fatal error:', err.message);
process.exit(1);
}
// Add global error handler to catch any unhandled errors
process.on('unhandledRejection', (reason, promise) => {
console.error('🚨 Unhandled rejection:', reason?.message || reason);
process.exit(1);
});
// Keep the process alive
setInterval(() => {}, 60000);
} catch (err) {
console.error('❌ Fatal error starting bot:', err.message);
console.error(err.stack);
process.exit(1);
}
})();