Pretty much full re-write, switched from node-irc to irc-framework, fixed some bugs, imrpoved some stuff, changed config from XML to yaml.
This commit is contained in:
BIN
.config.yaml.kate-swp
Normal file
BIN
.config.yaml.kate-swp
Normal file
Binary file not shown.
3
.gitignore
vendored
3
.gitignore
vendored
@@ -130,4 +130,5 @@ dist
|
|||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
|
||||||
config.xml
|
# Ignore the normal config. (Used by me for testing.)
|
||||||
|
config.yaml
|
||||||
|
|||||||
63
README.md
63
README.md
@@ -1,18 +1,69 @@
|
|||||||
# Discord-userbot-to-irc
|
# Discord-userbot-to-irc
|
||||||
A crappy group chat to a IRC room bridge written in node </3
|
A crappy group chat to a IRC room bridge written in node </3
|
||||||
|
|
||||||
|
## Features:
|
||||||
|
- Multi-Bridge Support - You can bridge multiple channels with multiple IRC rooms all with one config.
|
||||||
|
- Reactions Bridging - When a user reacts to a Discord message, the bridge sends a notification to IRC :D
|
||||||
|
- Attachments Bridging - Automatically forwards links to images and attachments from Discord messages to IRC
|
||||||
|
- TLS/Non-TLS IRC Support - Works with both secure (TLS) and standard IRC ports.
|
||||||
|
- Group chat bridges - Since this all works with a selfbot it means that you can bridge a Discord group chat to a IRC room.
|
||||||
|
- YAML Configuration - Simple and a human readable config.
|
||||||
|
|
||||||
|
|
||||||
# What you need to run this:
|
# What you need to run this:
|
||||||
|
|
||||||
|
- Node.js v18+
|
||||||
|
- `npm` package manager
|
||||||
|
|
||||||
```
|
```
|
||||||
Dependecies:
|
Dependecies:
|
||||||
xml2js
|
"discord.js-selfbot-v13": "^2.10.0",
|
||||||
discord.js-selfbot-v13
|
"irc-framework": "^3.0.0",
|
||||||
irc
|
"yaml": "^2.3.1"
|
||||||
```
|
```
|
||||||
### You also need a discord user token.
|
|
||||||
|
|
||||||
Before you run it edit the example.config.xml file with all the correct informatiion and rename it to config.xml
|
## Before running:
|
||||||
|
What you gonna need:
|
||||||
|
|
||||||
|
- A Discord user or bot token.
|
||||||
|
- An IRC room.
|
||||||
|
- Discord group/channel ID
|
||||||
|
- A server or machine to run the bot on.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
1. Clone the repository:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://foundry.fsky.io/purplebored/Discord-userbot-to-irc.git
|
||||||
|
cd Discord-userbot-to-irc
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Configuration:
|
||||||
|
|
||||||
|
Rename the `example.config.yaml` file to config.yaml and set it up to your liking.
|
||||||
|
|
||||||
|
## Config:
|
||||||
|
You can easaily enable or disable the logging of messeges or the raw IRC info for debuging by switching `debug: false` to `debug: true`, and the same with `logForward`
|
||||||
|
|
||||||
|
## How to run it:
|
||||||
|
Just run:
|
||||||
|
|
||||||
## To run it just run:
|
|
||||||
```
|
```
|
||||||
node bot.js
|
node bot.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Notes:
|
||||||
|
|
||||||
|
- Make sure your Discord selfbot token is kept private.
|
||||||
|
- For secure IRC connections, ensure `tls: true` and correct port
|
||||||
|
|
||||||
|
# Warning:
|
||||||
|
I would not reccomend using this in a active room since that might get the bot/userbot rate limited which is not good !
|
||||||
|
|
||||||
|
Also Using Userbots is against Discord's Terms of Service so your account/bot might get deactived. This has not happen yet but it is still possible.
|
||||||
|
|||||||
240
bot.js
240
bot.js
@@ -1,122 +1,218 @@
|
|||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const xml2js = require('xml2js');
|
const YAML = require("yaml");
|
||||||
const { Client, Intents } = require('discord.js-selfbot-v13');
|
const { Client, Intents } = require("discord.js-selfbot-v13");
|
||||||
const irc = require('irc');
|
const IRC = require("irc-framework");
|
||||||
|
|
||||||
// Load config.xml
|
// Load config.yaml
|
||||||
let config;
|
let config;
|
||||||
const parser = new xml2js.Parser({ explicitArray: false });
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const xmlData = fs.readFileSync('config.xml', 'utf8');
|
const file = fs.readFileSync("config.yaml", "utf8");
|
||||||
parser.parseString(xmlData, (err, result) => {
|
config = YAML.parse(file);
|
||||||
if (err) throw err;
|
|
||||||
config = result.BridgeConfig;
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Failed to load or parse config.xml:', e);
|
console.error("Failed to load or parse config.yaml:", e);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const DISCORD_TOKEN = config.Discord.Token;
|
const DISCORD_TOKEN = config.discord.token;
|
||||||
const bridges = Array.isArray(config.Bridges.Bridge)
|
const DEBUG = config.debug === true;
|
||||||
? config.Bridges.Bridge
|
const LOG_FORWARD = config.logForward === true;
|
||||||
: [config.Bridges.Bridge];
|
const bridges = config.bridges;
|
||||||
|
|
||||||
// Create Discord client
|
// Discord client
|
||||||
const discordClient = new Client({
|
const discordClient = new Client({
|
||||||
checkUpdate: false,
|
checkUpdate: false,
|
||||||
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]
|
intents: [
|
||||||
|
Intents.FLAGS.GUILDS,
|
||||||
|
Intents.FLAGS.GUILD_MESSAGES,
|
||||||
|
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Map to hold IRC clients and their config
|
// Map IRC clients
|
||||||
const ircClients = new Map();
|
const ircClients = new Map();
|
||||||
|
|
||||||
// Helper function to create and connect an IRC client for each bridge
|
// Logging helpers
|
||||||
|
function logDebug(...args) {
|
||||||
|
if (DEBUG) console.log(...args);
|
||||||
|
}
|
||||||
|
function logForward(...args) {
|
||||||
|
if (LOG_FORWARD) console.log(...args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create IRC client for a bridge
|
||||||
function createIRCClient(bridge) {
|
function createIRCClient(bridge) {
|
||||||
const ircConfig = bridge.IRC;
|
const ircConfig = bridge.irc;
|
||||||
const discordChannelId = bridge.Discord.ChannelId;
|
const discordChannelId = bridge.discordChannelId;
|
||||||
|
|
||||||
const server = ircConfig.Server;
|
const client = new IRC.Client();
|
||||||
const port = parseInt(ircConfig.Port, 10);
|
|
||||||
const nick = ircConfig.Nick;
|
|
||||||
const channel = ircConfig.Channel;
|
|
||||||
|
|
||||||
const client = new irc.Client(server, nick, {
|
client.connect({
|
||||||
channels: [channel],
|
host: ircConfig.server,
|
||||||
port: port,
|
port: parseInt(ircConfig.port, 10),
|
||||||
autoConnect: false
|
nick: ircConfig.nick,
|
||||||
|
password: ircConfig.password || undefined,
|
||||||
|
tls: ircConfig.tls || false,
|
||||||
|
tlsOptions: {
|
||||||
|
servername: ircConfig.server,
|
||||||
|
rejectUnauthorized: false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', (message) => {
|
client.on("connecting", () =>
|
||||||
console.error(`IRC error on ${server} (${channel}):`, message);
|
logDebug(`🔌 Connecting to ${ircConfig.server}:${ircConfig.port} ...`)
|
||||||
|
);
|
||||||
|
client.on("connected", () =>
|
||||||
|
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}`)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
client.on("join", (event) =>
|
||||||
|
logDebug(`🎉 Joined ${event.channel} as ${event.nick}`)
|
||||||
|
);
|
||||||
|
client.on("error", (event) =>
|
||||||
|
console.error(`IRC error on ${ircConfig.server}:`, event)
|
||||||
|
);
|
||||||
|
client.on("socket close", () =>
|
||||||
|
logDebug(`❌ Socket closed for ${ircConfig.server}`)
|
||||||
|
);
|
||||||
|
client.on("socket error", (err) =>
|
||||||
|
console.error(`⚠️ Socket error on ${ircConfig.server}:`, err)
|
||||||
|
);
|
||||||
|
|
||||||
client.on('message', (from, to, message) => {
|
client.on("message", (event) => {
|
||||||
// Avoid echoing own messages
|
if (event.nick === ircConfig.nick) return; // Skip self
|
||||||
if (from === nick) return;
|
const ircMessage = `<${event.nick}> ${event.message}`;
|
||||||
|
|
||||||
const ircMessage = `<${from}> ${message}`;
|
|
||||||
const discordChannel = discordClient.channels.cache.get(discordChannelId);
|
const discordChannel = discordClient.channels.cache.get(discordChannelId);
|
||||||
if (discordChannel) {
|
if (discordChannel) discordChannel.send(ircMessage).catch(console.error);
|
||||||
discordChannel.send(ircMessage).catch(console.error);
|
|
||||||
} else {
|
|
||||||
console.warn(`Discord channel ${discordChannelId} not found.`);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return { client, server, channel, nick, discordChannelId };
|
client.on("relaymsg", (event) => {
|
||||||
|
const discordChannel = discordClient.channels.cache.get(discordChannelId);
|
||||||
|
if (discordChannel)
|
||||||
|
discordChannel.send(`[relay ${event.nick}] ${event.message}`).catch(console.error);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
client.on("raw", (event) => console.log("RAW:", event.line));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize all IRC clients
|
return { client, channel: ircConfig.channel, nick: ircConfig.nick, discordChannelId };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize IRC clients
|
||||||
for (const bridge of bridges) {
|
for (const bridge of bridges) {
|
||||||
const { client, server, channel, nick } = createIRCClient(bridge);
|
const { client, channel, nick, discordChannelId } = createIRCClient(bridge);
|
||||||
ircClients.set(client, { server, channel, nick, discordChannelId: bridge.Discord.ChannelId });
|
ircClients.set(client, { channel, nick, discordChannelId });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect all IRC clients once Discord is ready
|
// Discord ready
|
||||||
discordClient.once('ready', () => {
|
discordClient.once("ready", () =>
|
||||||
console.log(`Logged in as ${discordClient.user.tag}`);
|
console.log(`Logged in as ${discordClient.user.tag}`)
|
||||||
|
);
|
||||||
|
|
||||||
for (const [ircClient, info] of ircClients.entries()) {
|
// Forward Discord messages → IRC
|
||||||
console.log(`Connecting to IRC server ${info.server} on channel ${info.channel}...`);
|
discordClient.on("messageCreate", async (message) => {
|
||||||
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;
|
if (message.author.bot) return;
|
||||||
|
|
||||||
for (const [ircClient, info] of ircClients.entries()) {
|
for (const [ircClient, info] of ircClients.entries()) {
|
||||||
if (message.channel.id === info.discordChannelId) {
|
if (message.channel.id !== info.discordChannelId) continue;
|
||||||
if (message.author.id === discordClient.user.id) return;
|
if (message.author.id === discordClient.user.id) return;
|
||||||
|
|
||||||
let quote = '';
|
// Fetch nickname
|
||||||
|
let nickname = message.author.username;
|
||||||
|
if (message.guild) {
|
||||||
|
try {
|
||||||
|
const member = await message.guild.members.fetch(message.author.id);
|
||||||
|
nickname = member ? member.displayName : message.author.username;
|
||||||
|
} catch (err) {
|
||||||
|
nickname = message.author.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle quoted replies
|
||||||
|
let quote = "";
|
||||||
if (message.reference && message.reference.messageId) {
|
if (message.reference && message.reference.messageId) {
|
||||||
try {
|
try {
|
||||||
const referencedMessage = await message.channel.messages.fetch(message.reference.messageId);
|
const referencedMessage = await message.channel.messages.fetch(
|
||||||
|
message.reference.messageId
|
||||||
|
);
|
||||||
if (referencedMessage) {
|
if (referencedMessage) {
|
||||||
const refAuthor = referencedMessage.author.username;
|
const refMember =
|
||||||
const refContent = referencedMessage.content || '[Embed/Attachment]';
|
referencedMessage.guild &&
|
||||||
const quotedLines = refContent.split('\n').map(line => `> ${line}`).join('\n');
|
(await referencedMessage.guild.members.fetch(
|
||||||
|
referencedMessage.author.id
|
||||||
|
).catch(() => null));
|
||||||
|
const refAuthor = refMember
|
||||||
|
? refMember.displayName
|
||||||
|
: 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`;
|
quote = `> ${refAuthor} said:\n${quotedLines}\n`;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.warn('Failed to fetch referenced message:', err);
|
logDebug("Failed to fetch referenced message:", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const discordMessage = `${quote}<${message.author.username}> ${message.content}`;
|
// Build message text
|
||||||
console.log(`Forwarding Discord message to IRC [${info.server} ${info.channel}]: ${discordMessage}`);
|
let discordMessage = `${quote}<${nickname}> ${message.content}`;
|
||||||
|
|
||||||
|
// Append attachment URLs (images/files)
|
||||||
|
if (message.attachments.size > 0) {
|
||||||
|
const urls = message.attachments.map((att) => att.url).join(" ");
|
||||||
|
discordMessage += ` [Attachments: ${urls}]`;
|
||||||
|
}
|
||||||
|
|
||||||
|
logForward(`Forwarding Discord → IRC [${info.channel}]: ${discordMessage}`);
|
||||||
ircClient.say(info.channel, discordMessage);
|
ircClient.say(info.channel, discordMessage);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forward reactions → IRC
|
||||||
|
discordClient.on("messageReactionAdd", async (reaction, user) => {
|
||||||
|
if (user.bot) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (reaction.partial) await reaction.fetch();
|
||||||
|
const message = reaction.message;
|
||||||
|
const channelId = message.channel.id;
|
||||||
|
|
||||||
|
for (const [ircClient, info] of ircClients.entries()) {
|
||||||
|
if (channelId !== info.discordChannelId) continue;
|
||||||
|
|
||||||
|
// Get nickname
|
||||||
|
let nickname = user.username;
|
||||||
|
if (message.guild) {
|
||||||
|
try {
|
||||||
|
const member = await message.guild.members.fetch(user.id);
|
||||||
|
nickname = member ? member.displayName : user.username;
|
||||||
|
} catch (err) {
|
||||||
|
nickname = user.username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const emoji = reaction.emoji.name;
|
||||||
|
const originalContent = message.content || "[Embed/Attachment]";
|
||||||
|
const reactionMessage = `<${nickname}> reacted with ${emoji} to "${originalContent}"`;
|
||||||
|
|
||||||
|
logForward(`Reaction → IRC [${info.channel}]: ${reactionMessage}`);
|
||||||
|
ircClient.say(info.channel, reactionMessage);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
logDebug("Failed to handle reaction:", err);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Login to Discord
|
// Login to Discord
|
||||||
discordClient.login(DISCORD_TOKEN).catch(err => {
|
discordClient.login(DISCORD_TOKEN).catch((err) =>
|
||||||
console.error('Failed to login to Discord:', err);
|
console.error("Failed to login to Discord:", err)
|
||||||
});
|
);
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
<BridgeConfig>
|
|
||||||
<Discord>
|
|
||||||
<Token>YOUR_DISCORD_TOKEN</Token>
|
|
||||||
</Discord>
|
|
||||||
<Bridges>
|
|
||||||
<Bridge>
|
|
||||||
<IRC>
|
|
||||||
<Server>irc.example1.net</Server>
|
|
||||||
<Port>6667</Port>
|
|
||||||
<Nick>MyIRCBot1</Nick>
|
|
||||||
<Channel>#channel1</Channel>
|
|
||||||
</IRC>
|
|
||||||
<Discord>
|
|
||||||
<ChannelId>DISCORD_CHANNEL_ID_1</ChannelId>
|
|
||||||
</Discord>
|
|
||||||
</Bridge>
|
|
||||||
<Bridge>
|
|
||||||
<IRC>
|
|
||||||
<Server>irc.example2.org</Server>
|
|
||||||
<Port>6667</Port>
|
|
||||||
<Nick>MyIRCBot2</Nick>
|
|
||||||
<Channel>#channel2</Channel>
|
|
||||||
</IRC>
|
|
||||||
<Discord>
|
|
||||||
<ChannelId>DISCORD_CHANNEL_ID_2</ChannelId>
|
|
||||||
</Discord>
|
|
||||||
</Bridge>
|
|
||||||
<!-- Add more Bridge entries as needed -->
|
|
||||||
</Bridges>
|
|
||||||
</BridgeConfig>
|
|
||||||
27
example.config.yaml
Normal file
27
example.config.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
discord:
|
||||||
|
token: "YOUR_DISCORD_TOKEN" # Insert your bot or user token here.
|
||||||
|
|
||||||
|
# Debugging options
|
||||||
|
debug: true # raw IRC + connection info
|
||||||
|
logForward: true # Discord -> IRC message forwarding logs
|
||||||
|
|
||||||
|
# Bridges
|
||||||
|
bridges:
|
||||||
|
- discordChannelId: "123456789012345678"
|
||||||
|
irc:
|
||||||
|
server: "irc.example.org"
|
||||||
|
port: 6697
|
||||||
|
tls: true
|
||||||
|
nick: "MyBot"
|
||||||
|
password: null # or "yourpassword" if required
|
||||||
|
channel: "#test"
|
||||||
|
|
||||||
|
# Adding more then one bridge
|
||||||
|
- discordChannelId: "987654321098765432"
|
||||||
|
irc:
|
||||||
|
server: "irc.other.net"
|
||||||
|
port: 6667
|
||||||
|
tls: false
|
||||||
|
nick: "OtherBot"
|
||||||
|
password: null
|
||||||
|
channel: "#another"
|
||||||
15
package-lock.json
generated
15
package-lock.json
generated
@@ -12,7 +12,8 @@
|
|||||||
"discord.js-selfbot-v13": "^3.4.5",
|
"discord.js-selfbot-v13": "^3.4.5",
|
||||||
"irc": "^0.5.2",
|
"irc": "^0.5.2",
|
||||||
"irc-framework": "^4.14.0",
|
"irc-framework": "^4.14.0",
|
||||||
"xml2js": "^0.6.2"
|
"xml2js": "^0.6.2",
|
||||||
|
"yaml": "^2.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@discordjs/builders": {
|
"node_modules/@discordjs/builders": {
|
||||||
@@ -1513,6 +1514,18 @@
|
|||||||
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/yaml": {
|
||||||
|
"version": "2.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
||||||
|
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
||||||
|
"license": "ISC",
|
||||||
|
"bin": {
|
||||||
|
"yaml": "bin.mjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/yargs": {
|
"node_modules/yargs": {
|
||||||
"version": "15.4.1",
|
"version": "15.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
|
||||||
|
|||||||
24
package.json
24
package.json
@@ -1,18 +1,16 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"name": "discord-irc-bridge",
|
||||||
"discord.js-selfbot-v13": "^3.4.5",
|
"version": "2.0.0",
|
||||||
"irc": "^0.5.2",
|
"description": "A Discord <-> IRC bridge using selfbot and irc-framework",
|
||||||
"irc-framework": "^4.14.0",
|
|
||||||
"xml2js": "^0.6.2"
|
|
||||||
},
|
|
||||||
"name": "bridge",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"main": "bot.js",
|
"main": "bot.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"start": "node bot.js"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"author": "Purplebored",
|
||||||
"author": "",
|
"license": "MIT",
|
||||||
"license": "ISC",
|
"dependencies": {
|
||||||
"description": ""
|
"discord.js-selfbot-v13": "^2.10.0",
|
||||||
|
"irc-framework": "^3.0.0",
|
||||||
|
"yaml": "^2.3.1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user