add: Bump up the version and add RELLAYMSG for IRC.

This commit is contained in:
2025-09-28 13:53:56 +02:00
parent 6ac41d3215
commit 20060d1130
5 changed files with 118 additions and 56 deletions

148
bot.js
View File

@@ -43,80 +43,114 @@ function logForward(...args) {
function createIRCClient(bridge) {
const ircConfig = bridge.irc;
const discordChannelId = bridge.discordChannelId;
const useRelayMsg = bridge.useRelayMsg === true;
const client = new IRC.Client();
client.connect({
host: ircConfig.server,
port: parseInt(ircConfig.port, 10),
nick: ircConfig.nick,
password: ircConfig.password || undefined,
tls: ircConfig.tls || false,
tlsOptions: {
servername: ircConfig.server,
rejectUnauthorized: false,
},
nick: ircConfig.nick,
password: ircConfig.password || undefined,
tls: ircConfig.tls || false,
tlsOptions: {
servername: ircConfig.server,
rejectUnauthorized: false,
},
});
client.state = {
hasOp: false,
relayMsgEnabled: useRelayMsg,
warnedRelayMsg: false,
};
client.on("connecting", () =>
logDebug(`Connecting to ${ircConfig.server}:${ircConfig.port} ...`)
logDebug(`Connecting to ${ircConfig.server}:${ircConfig.port} ...`)
);
client.on("connected", () =>
logDebug(`TCP connection established to ${ircConfig.server}`)
logDebug(`TCP connection established to ${ircConfig.server}`)
);
client.on("registered", () => {
console.log(
`Connected to IRC ${ircConfig.server} as ${ircConfig.nick}, joining ${ircConfig.channel}`
);
client.join(ircConfig.channel, () =>
logDebug(`Sent JOIN for ${ircConfig.channel}`)
logDebug(`Sent JOIN for ${ircConfig.channel}`)
);
});
client.on("join", (event) =>
logDebug(`Joined ${event.channel} as ${event.nick}`)
);
client.on("names", (event) => {
const myNick = ircConfig.nick;
const modes = event.users[myNick];
if (Array.isArray(modes) && modes.includes("@")) {
client.state.hasOp = true;
logDebug(`${myNick} detected as +o from NAMES list`);
}
});
client.on("mode", (event) => {
if (event.target === ircConfig.channel) {
for (const m of event.modes) {
if (m.mode === "+o" && m.param === ircConfig.nick) {
client.state.hasOp = true;
logDebug(`${ircConfig.nick} gained +o (channel operator)`);
} else if (m.mode === "-o" && m.param === ircConfig.nick) {
client.state.hasOp = false;
logDebug(`${ircConfig.nick} lost +o (channel operator)`);
}
}
}
});
client.on("error", (event) =>
console.error(`IRC error on ${ircConfig.server}:`, event)
console.error(`IRC error on ${ircConfig.server}:`, event)
);
client.on("socket close", () =>
logDebug(`Socket closed for ${ircConfig.server}`)
logDebug(`Socket closed for ${ircConfig.server}`)
);
client.on("socket error", (err) =>
console.error(`Socket error on ${ircConfig.server}:`, err)
console.error(`Socket error on ${ircConfig.server}:`, err)
);
// Handle IRC → Discord
client.on("message", (event) => {
if (event.nick === ircConfig.nick) return; // Skip self
if (event.nick === ircConfig.nick || event.nick.endsWith("/dc")) return;
const ircMessage = `<${event.nick}> ${event.message}`;
const discordChannel = discordClient.channels.cache.get(discordChannelId);
if (discordChannel) discordChannel.send(ircMessage).catch(console.error);
});
client.on("relaymsg", (event) => {
const discordChannel = discordClient.channels.cache.get(discordChannelId);
if (discordChannel)
discordChannel
.send(`[relay ${event.nick}] ${event.message}`)
.catch(console.error);
});
client.on("relaymsg", (event) => {
const discordChannel = discordClient.channels.cache.get(discordChannelId);
if (discordChannel)
discordChannel.send(`<${event.nick}> ${event.message}`).catch(console.error);
});
if (DEBUG) {
client.on("raw", (event) => console.log("RAW:", event.line));
}
if (DEBUG) {
client.on("raw", (event) => console.log("RAW:", event.line));
}
return { client, channel: ircConfig.channel, nick: ircConfig.nick, discordChannelId };
return {
client,
channel: ircConfig.channel,
nick: ircConfig.nick,
discordChannelId,
useRelayMsg,
};
}
// Initialize IRC clients
for (const bridge of bridges) {
const { client, channel, nick, discordChannelId } = createIRCClient(bridge);
ircClients.set(client, { channel, nick, discordChannelId });
const { client, channel, nick, discordChannelId, useRelayMsg } =
createIRCClient(bridge);
ircClients.set(client, { channel, nick, discordChannelId, useRelayMsg });
}
// Discord ready
discordClient.once("ready", () =>
console.log(`Logged in as ${discordClient.user.tag}`)
console.log(`Logged in as ${discordClient.user.tag}`)
);
// Forward Discord messages → IRC
@@ -145,16 +179,14 @@ discordClient.on("messageCreate", async (message) => {
const referencedMessage = await message.channel.messages.fetch(
message.reference.messageId
);
if (referencedMessage.content) {
let refAuthor = referencedMessage.author.username;
if (referencedMessage.guild) {
const member = await referencedMessage.guild.members
.fetch(referencedMessage.author.id)
.catch(() => null);
.fetch(referencedMessage.author.id)
.catch(() => null);
if (member) refAuthor = member.displayName;
}
const originalText = referencedMessage.content.replace(/\n/g, " ");
quote = `<${refAuthor}> said: ${originalText} | `;
}
@@ -163,17 +195,35 @@ discordClient.on("messageCreate", async (message) => {
}
}
// Build message text
let discordMessage = `${quote}<${nickname}> ${message.content}`;
// Append attachment URLs
// Build message
let baseMessage = message.content;
if (quote) baseMessage = `${quote}${baseMessage}`;
if (message.attachments.size > 0) {
const urls = message.attachments.map((att) => att.url).join(" ");
discordMessage += ` [Attachments: ${urls}]`;
baseMessage += ` [Attachments: ${urls}]`;
}
const privmsgMessage = `<${nickname}> ${baseMessage}`;
logForward(`Forwarding Discord → IRC [${info.channel}]: ${discordMessage}`);
ircClient.say(info.channel, discordMessage);
logForward(`Forwarding Discord → IRC [${info.channel}]: ${privmsgMessage}`);
// --- RELAYMSG logic ---
if (info.useRelayMsg) {
if (ircClient.state.hasOp) {
const relayNick = `${nickname}/dc`;
ircClient.raw(`RELAYMSG ${info.channel} ${relayNick} :${baseMessage}`);
} else {
if (!ircClient.state.warnedRelayMsg) {
ircClient.say(
info.channel,
`[Bridge] Missing +o, falling back to PRIVMSG (RELAYMSG disabled)`
);
ircClient.state.warnedRelayMsg = true;
}
ircClient.say(info.channel, privmsgMessage);
}
} else {
ircClient.say(info.channel, privmsgMessage);
}
}
});
@@ -205,7 +255,15 @@ discordClient.on("messageReactionAdd", async (reaction, user) => {
const reactionMessage = `<${nickname}> reacted with ${emoji} to "${originalContent}"`;
logForward(`Reaction → IRC [${info.channel}]: ${reactionMessage}`);
ircClient.say(info.channel, reactionMessage);
if (info.useRelayMsg && ircClient.state.hasOp) {
const relayNick = `${nickname}/dc`;
ircClient.raw(
`RELAYMSG ${info.channel} ${relayNick} :${reactionMessage}`
);
} else {
ircClient.say(info.channel, reactionMessage);
}
}
} catch (err) {
logDebug("Failed to handle reaction:", err);
@@ -214,5 +272,5 @@ discordClient.on("messageReactionAdd", async (reaction, user) => {
// Login to Discord
discordClient.login(DISCORD_TOKEN).catch((err) =>
console.error("Failed to login to Discord:", err)
console.error("Failed to login to Discord:", err)
);