Discord-userbot-to-irc/bot.js

122 lines
3.9 KiB
JavaScript

const fs = require('fs');
const xml2js = require('xml2js');
const { Client, Intents } = require('discord.js-selfbot-v13');
const irc = require('irc');
// Load config.xml
let config;
const parser = new xml2js.Parser({ explicitArray: false });
try {
const xmlData = fs.readFileSync('config.xml', 'utf8');
parser.parseString(xmlData, (err, result) => {
if (err) throw err;
config = result.BridgeConfig;
});
} catch (e) {
console.error('Failed to load or parse config.xml:', e);
process.exit(1);
}
const DISCORD_TOKEN = config.Discord.Token;
const bridges = Array.isArray(config.Bridges.Bridge)
? config.Bridges.Bridge
: [config.Bridges.Bridge];
// Create Discord client
const discordClient = new Client({
checkUpdate: false,
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]
});
// Map to hold IRC clients and their config
const ircClients = new Map();
// Helper function to create and connect an IRC client for each bridge
function createIRCClient(bridge) {
const ircConfig = bridge.IRC;
const discordChannelId = bridge.Discord.ChannelId;
const server = ircConfig.Server;
const port = parseInt(ircConfig.Port, 10);
const nick = ircConfig.Nick;
const channel = ircConfig.Channel;
const client = new irc.Client(server, nick, {
channels: [channel],
port: port,
autoConnect: false
});
client.on('error', (message) => {
console.error(`IRC error on ${server} (${channel}):`, message);
});
client.on('message', (from, to, message) => {
// Avoid echoing own messages
if (from === nick) return;
const ircMessage = `<${from}> ${message}`;
const discordChannel = discordClient.channels.cache.get(discordChannelId);
if (discordChannel) {
discordChannel.send(ircMessage).catch(console.error);
} else {
console.warn(`Discord channel ${discordChannelId} not found.`);
}
});
return { client, server, channel, nick, discordChannelId };
}
// Initialize all IRC clients
for (const bridge of bridges) {
const { client, server, channel, nick } = createIRCClient(bridge);
ircClients.set(client, { server, channel, nick, discordChannelId: bridge.Discord.ChannelId });
}
// Connect all IRC clients once Discord is ready
discordClient.once('ready', () => {
console.log(`Logged in as ${discordClient.user.tag}`);
for (const [ircClient, info] of ircClients.entries()) {
console.log(`Connecting to IRC server ${info.server} on channel ${info.channel}...`);
ircClient.connect(5, () => {
console.log(`Connected to IRC server ${info.server} channel ${info.channel}`);
});
}
});
// Forward Discord messages to corresponding IRC channel, handling replies as quotes
discordClient.on('messageCreate', async (message) => {
if (message.author.bot) return;
for (const [ircClient, info] of ircClients.entries()) {
if (message.channel.id === info.discordChannelId) {
if (message.author.id === discordClient.user.id) return;
let quote = '';
if (message.reference && message.reference.messageId) {
try {
const referencedMessage = await message.channel.messages.fetch(message.reference.messageId);
if (referencedMessage) {
const refAuthor = referencedMessage.author.username;
const refContent = referencedMessage.content || '[Embed/Attachment]';
const quotedLines = refContent.split('\n').map(line => `> ${line}`).join('\n');
quote = `> ${refAuthor} said:\n${quotedLines}\n`;
}
} catch (err) {
console.warn('Failed to fetch referenced message:', err);
}
}
const discordMessage = `${quote}<${message.author.username}> ${message.content}`;
console.log(`Forwarding Discord message to IRC [${info.server} ${info.channel}]: ${discordMessage}`);
ircClient.say(info.channel, discordMessage);
}
}
});
// Login to Discord
discordClient.login(DISCORD_TOKEN).catch(err => {
console.error('Failed to login to Discord:', err);
});