Compare commits
10 Commits
7f010a009b
...
8d340db915
| Author | SHA1 | Date | |
|---|---|---|---|
| 8d340db915 | |||
| fe7b30908e | |||
| e2e6fa8e8a | |||
| d862a7aa37 | |||
| d620b20ecf | |||
| 42405dd268 | |||
| da4cc21558 | |||
| c36807e2aa | |||
| fd349e20fc | |||
| 4e80f42510 |
@@ -1,3 +1,4 @@
|
||||
node_modules
|
||||
.git
|
||||
config.json
|
||||
avatars
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -142,3 +142,4 @@ dist
|
||||
|
||||
config.json
|
||||
state.json
|
||||
avatars
|
||||
18
commands/status.js
Normal file
18
commands/status.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const { SlashCommandBuilder, ActivityType } = require('discord.js');
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('status')
|
||||
.setDescription('Change the bot\'s status message')
|
||||
.addStringOption(option =>
|
||||
option.setName('message')
|
||||
.setDescription('The new status message')
|
||||
.setRequired(true)
|
||||
),
|
||||
async execute(interaction) {
|
||||
const message = interaction.options.getString('message');
|
||||
console.log(`${interaction.user.tag} is changing the status to ${message}`);
|
||||
interaction.client.user.setActivity(message, { type: ActivityType.Custom });
|
||||
await interaction.reply({ content: `Status updated to: ${message}`, ephemeral: true });
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"token": "bot token go here",
|
||||
"status": "looking for x.com links",
|
||||
"avatarInterval": 15,
|
||||
"parentsAndOrGuardians": [
|
||||
"230659159450845195",
|
||||
"297983197990354944"
|
||||
|
||||
@@ -4,3 +4,4 @@ services:
|
||||
build: .
|
||||
volumes:
|
||||
- ./config.json:/usr/src/bot/config.json
|
||||
- ./avatars:/usr/src/bot/avatars
|
||||
104
index.js
104
index.js
@@ -17,6 +17,7 @@ const client = new Client({
|
||||
]
|
||||
});
|
||||
|
||||
// build the button below the message that swaps the URL
|
||||
const { ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
|
||||
const swapRow = new ActionRowBuilder()
|
||||
.addComponents(
|
||||
@@ -26,35 +27,38 @@ const swapRow = new ActionRowBuilder()
|
||||
.setStyle(ButtonStyle.Secondary),
|
||||
);
|
||||
|
||||
// the main function that swaps the URL, takes
|
||||
function convertURL(url, regex, domain) {
|
||||
const match = url.match(regex);
|
||||
if (match) {
|
||||
console.log(`Converting ${url} to ${domain}`)
|
||||
return `https://${domain}/${match[1]}/status/${match[2]}`;
|
||||
}
|
||||
}
|
||||
|
||||
// called by the swap button, swaps girlcock links to fxtwitter, and back again if needed
|
||||
function swapify(url) {
|
||||
const girlcockRegex = /https?:\/\/girlcockx\.com\/(.*?)\/status\/(\d+)/;
|
||||
const fxtwitterRegex = /https?:\/\/fxtwitter\.com\/(.*?)\/status\/(\d+)/;
|
||||
let link = '';
|
||||
if (url.match(girlcockRegex)) {
|
||||
const original = url.match(girlcockRegex)[0];
|
||||
const profile = url.match(girlcockRegex)[1];
|
||||
const stub = url.match(girlcockRegex)[2];
|
||||
console.log(`Button: Asked to swap ${url}, fxtwittering it`);
|
||||
link = `https://fxtwitter.com/${profile}/status/${stub}`;
|
||||
} else if (url.match(fxtwitterRegex)) {
|
||||
const original = url.match(fxtwitterRegex)[0];
|
||||
const profile = url.match(fxtwitterRegex)[1];
|
||||
const stub = url.match(fxtwitterRegex)[2];
|
||||
console.log(`Button: Asked to swap ${url}, cocking it again`);
|
||||
link = `https://girlcockx.com/${profile}/status/${stub}`;
|
||||
}
|
||||
return link;
|
||||
const fixupxRegex = /https?:\/\/fixupx\.com\/(.*?)\/status\/(\d+)/;
|
||||
if (url.match(girlcockRegex)) return convertURL(url, girlcockRegex, "fxtwitter.com");
|
||||
if (url.match(fxtwitterRegex)) return convertURL(url, fxtwitterRegex, "fixupx.com");
|
||||
if (url.match(fixupxRegex)) return convertURL(url, fixupxRegex, "girlcockx.com");
|
||||
// if we got this far, somethings not right but we'll try twitter before giving up
|
||||
const twitterRegex = /https?:\/\/x\.com\/(.*?)\/status\/(\d+)/;
|
||||
if (url.match(twitterRegex)) return convertURL(url, twitterRegex, "girlcockx.com");
|
||||
return url; // give up, we'll just return the original URL
|
||||
}
|
||||
|
||||
// what actually listens for the button press and calls swapify
|
||||
client.on(Events.InteractionCreate, async interaction => {
|
||||
if (interaction.isButton()) {
|
||||
if (interaction.customId === 'swap_twitter') {
|
||||
try {
|
||||
const regex = /https?:\/\/girlcockx\.com\/(.*?)\/status\/(\d+)/;
|
||||
await interaction.update(swapify(interaction.message.content));
|
||||
} catch (error) {
|
||||
} catch (error) { // honestly the swapify function has its own error handling and it should be fine but whatever
|
||||
console.error(error);
|
||||
await interaction.reply({ content: 'I couldn\'t swap them for some reason', ephemeral: true });
|
||||
await interaction.reply({ content: "Something went wrong trying to swap the URL", ephemeral: true });
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -64,56 +68,36 @@ client.on(Events.InteractionCreate, async interaction => {
|
||||
client.once(Events.ClientReady, readyClient => {
|
||||
console.log(`Discord: Connected as ${readyClient.user.tag}`);
|
||||
client.user.setActivity(config.status, { type: ActivityType.Custom });
|
||||
const avatarRotation = require('./lib/avatarRotation');
|
||||
avatarRotation.init(client);
|
||||
});
|
||||
client.login(config.token);
|
||||
|
||||
client.on(Events.MessageCreate, message => {
|
||||
// if we smell a twitter link, girlcock it!
|
||||
const regexProfile = /https?:\/\/x\.com\/(.*?)\/status\/(\d+)/;
|
||||
if (message.content.match(regexProfile)) {
|
||||
const original = message.content.match(regexProfile)[0]
|
||||
const profile = message.content.match(regexProfile)[1]
|
||||
const stub = message.content.match(regexProfile)[2]
|
||||
console.log(`Chat: Detected ${original}, girlcocking it!`);
|
||||
const cocklink = `https://girlcockx.com/${profile}/status/${stub}`
|
||||
console.log(`Girlcock: Converted to ${cocklink}`)
|
||||
const twitterRegex = /https?:\/\/x\.com\/(.*?)\/status\/(\d+)/;
|
||||
const regexProfile = message.content.match(twitterRegex);
|
||||
if (regexProfile) {
|
||||
const cocklink = convertURL(regexProfile[0], twitterRegex, "girlcockx.com")
|
||||
message.channel.send({ content: cocklink, flags: MessageFlags.SuppressNotifications, components: [swapRow] })
|
||||
message.suppressEmbeds().catch(err =>
|
||||
// this next bit just cuts down the error to the important part, which will usually end up being "no permissions"
|
||||
console.error(err.stack?.split('\n')[0] || err.message || String(err).split('\n')[0])
|
||||
console.error("Removing original embed failed: " + err.stack?.split('\n')[0] || err.message || String(err).split('\n')[0])
|
||||
)
|
||||
}
|
||||
|
||||
// hehe an eval :3
|
||||
if (message.content.startsWith('!eval') && config.parentsAndOrGuardians.includes(message.author.id)) {
|
||||
let code = message.content.substring('!eval'.length).trim();
|
||||
|
||||
// yeah a machine may have wrote this part
|
||||
const codeBlockRegex = /```(?:js)?\n?([\s\S]+)```/;
|
||||
const match = code.match(codeBlockRegex);
|
||||
|
||||
if (match) {
|
||||
code = match[1];
|
||||
}
|
||||
|
||||
try {
|
||||
eval(code);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
// hehe we do a little if stacking
|
||||
if (message.content.startsWith('!status') && config.parentsAndOrGuardians.includes(message.author.id)) {
|
||||
let status = message.content.substring('!status'.length).trim();
|
||||
client.user.setActivity(status, { type: ActivityType.Custom });
|
||||
config.status = status;
|
||||
}
|
||||
|
||||
// wouldnt it be funny to react to 1 in like 10000 messages with emoji from a list
|
||||
if (Math.random() < 0.0001 && !message.author.bot) {
|
||||
// wouldnt it be funny to react to 1 in like 1000 messages with emoji from a list
|
||||
if (Math.random() < 0.001 && !message.author.bot) {
|
||||
const customEmojis = [
|
||||
'Shitten:1430413059574206555',
|
||||
'BLOWSUP:1430413011918651503'
|
||||
'BLOWSUP:1430413011918651503',
|
||||
'grin_cat:1445254917991436449',
|
||||
'R_:1461939667657298081',
|
||||
'crumble:1461939666121920605',
|
||||
'jumble:1461939664306045008',
|
||||
'scrumble:1461939662930055278',
|
||||
'Chundle:1461939661541867713',
|
||||
'chimgen:1461939660212408351'
|
||||
];
|
||||
const randomEmoji = customEmojis[Math.floor(Math.random() * customEmojis.length)];
|
||||
message.react(randomEmoji);
|
||||
@@ -141,17 +125,15 @@ const mpregs = [
|
||||
'mpreg17:1434030048586760303',
|
||||
'mpreg18:1434030067419451402',
|
||||
'mpreg19:1434030085794435092'
|
||||
]
|
||||
|
||||
];
|
||||
client.on(Events.MessageReactionAdd, (reaction, user) => {
|
||||
if (reaction.emoji.name === '🫃' && !user.bot) {
|
||||
reaction.message.react('🫃')
|
||||
reaction.message.react('🫃');
|
||||
for (const mpreg of mpregs) {
|
||||
reaction.message.react(mpreg).catch(err => console.error(err.stack?.split('\n')[0] || err.message || String(err).split('\n')[0]))
|
||||
reaction.message.react(mpreg).catch(err => console.error(err.stack?.split('\n')[0] || err.message || String(err).split('\n')[0]));
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// command handling for ./commands
|
||||
const fs = require('fs');
|
||||
|
||||
77
lib/avatarRotation.js
Normal file
77
lib/avatarRotation.js
Normal file
@@ -0,0 +1,77 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const config = require('../config.json');
|
||||
|
||||
const AVATAR_DIR = path.join(__dirname, '../avatars');
|
||||
let avatarFiles = [];
|
||||
let currentAvatarIndex = 0;
|
||||
let timer = null;
|
||||
|
||||
function loadAvatars() {
|
||||
try {
|
||||
if (!fs.existsSync(AVATAR_DIR)) {
|
||||
fs.mkdirSync(AVATAR_DIR);
|
||||
console.log('Avatars: Created avatars directory');
|
||||
return;
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(AVATAR_DIR);
|
||||
avatarFiles = files.filter(file => /\.(jpg|jpeg|png|gif|webp)$/i.test(file));
|
||||
|
||||
// shuffle
|
||||
for (let i = avatarFiles.length - 1; i > 0; i--) {
|
||||
const j = Math.floor(Math.random() * (i + 1));
|
||||
[avatarFiles[i], avatarFiles[j]] = [avatarFiles[j], avatarFiles[i]];
|
||||
}
|
||||
|
||||
console.log(`Avatars: Loaded ${avatarFiles.length} avatars`);
|
||||
currentAvatarIndex = 0; // Reset index on reload
|
||||
} catch (err) {
|
||||
console.error('Avatars: Error loading avatars:', err);
|
||||
}
|
||||
}
|
||||
|
||||
function rotateAvatar(client) {
|
||||
if (avatarFiles.length === 0) return;
|
||||
|
||||
const avatarFile = avatarFiles[currentAvatarIndex];
|
||||
const avatarPath = path.join(AVATAR_DIR, avatarFile);
|
||||
|
||||
try {
|
||||
client.user.setAvatar(avatarPath);
|
||||
console.log(`Avatars: Changed avatar to ${avatarFile}`);
|
||||
} catch (err) {
|
||||
console.error(`Avatars: Failed to set avatar to ${avatarFile}:`, err);
|
||||
}
|
||||
|
||||
currentAvatarIndex = (currentAvatarIndex + 1) % avatarFiles.length;
|
||||
}
|
||||
|
||||
function init(client) {
|
||||
loadAvatars();
|
||||
|
||||
// Watch for changes in the avatars directory
|
||||
let fsWait = null;
|
||||
fs.watch(AVATAR_DIR, (eventType, filename) => {
|
||||
if (filename) {
|
||||
if (fsWait) clearTimeout(fsWait);
|
||||
fsWait = setTimeout(() => {
|
||||
console.log(`Avatars: Detected change in avatars directory`);
|
||||
loadAvatars();
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
const intervalMinutes = config.avatarInterval || 15;
|
||||
const intervalMs = intervalMinutes * 60 * 1000;
|
||||
|
||||
console.log(`Avatars: Starting avatar rotation every ${intervalMinutes} minutes`);
|
||||
|
||||
// Initial rotation
|
||||
rotateAvatar(client);
|
||||
|
||||
// make it wait every interval before rotating
|
||||
timer = setInterval(() => rotateAvatar(client), intervalMs);
|
||||
}
|
||||
|
||||
module.exports = { init };
|
||||
Reference in New Issue
Block a user