2022-08-28 17:03:15 +02:00
|
|
|
|
import { SlashCommandBuilder } from 'discord.js';
|
|
|
|
|
import { EmbedBuilder } from 'discord.js';
|
2023-06-04 19:02:30 +02:00
|
|
|
|
import { TwitterApi } from 'twitter-api-v2';
|
2022-08-14 22:28:37 +02:00
|
|
|
|
import fetch from 'node-fetch';
|
|
|
|
|
import os from 'node:os';
|
|
|
|
|
import fs from 'node:fs';
|
2023-04-04 18:06:05 +02:00
|
|
|
|
import util from 'node:util';
|
|
|
|
|
import stream from 'node:stream';
|
2022-08-14 22:28:37 +02:00
|
|
|
|
|
|
|
|
|
import db from '../../models/index.js';
|
2024-07-04 19:15:29 +02:00
|
|
|
|
import wordToCensor from '../../json/censor.json' with {type: 'json'};
|
2022-08-14 22:28:37 +02:00
|
|
|
|
const { twiConsumer, twiConsumerSecret, twiToken, twiTokenSecret, twiChannel, twiLogChannel } = process.env;
|
|
|
|
|
|
|
|
|
|
const Blacklists = db.Blacklists;
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
data: new SlashCommandBuilder()
|
|
|
|
|
.setName('tweet')
|
2023-04-20 19:50:41 +02:00
|
|
|
|
.setDescription('Send tweet from the bot twitter account. Please do not use it for advertisement and keep it english')
|
2022-08-14 22:28:37 +02:00
|
|
|
|
.addStringOption(option =>
|
|
|
|
|
option.setName('content')
|
2023-04-20 19:50:41 +02:00
|
|
|
|
.setDescription('!THIS IS NOT FEEDBACK! The content of the tweet you want to send me.')
|
2022-08-14 22:28:37 +02:00
|
|
|
|
.setRequired(false))
|
|
|
|
|
.addAttachmentOption(option =>
|
|
|
|
|
option.setName('image')
|
|
|
|
|
.setDescription('Optional attachment (Image only.)')
|
|
|
|
|
.setRequired(false)),
|
2022-08-28 17:03:15 +02:00
|
|
|
|
category: 'fun',
|
2022-08-14 23:28:24 +02:00
|
|
|
|
ratelimit: 3,
|
2022-12-19 04:40:49 +01:00
|
|
|
|
cooldown: 86400,
|
2023-04-15 19:32:35 +02:00
|
|
|
|
guildOnly: true,
|
2022-08-28 17:03:15 +02:00
|
|
|
|
async execute(interaction, args, client) {
|
2022-09-01 01:43:59 +02:00
|
|
|
|
const content = args.content;
|
|
|
|
|
const attachment = args.image;
|
2023-04-04 18:06:05 +02:00
|
|
|
|
|
2022-08-28 17:03:15 +02:00
|
|
|
|
if (!content && !attachment) {
|
2022-08-16 22:25:23 +02:00
|
|
|
|
return interaction.reply({ content: 'Uh oh! You are missing any content for me to tweet!', ephemeral: true });
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-15 15:14:03 +02:00
|
|
|
|
await interaction.deferReply({ ephemeral: false });
|
2022-08-28 17:03:15 +02:00
|
|
|
|
let tweet = content;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
const date = new Date();
|
2023-04-15 19:32:35 +02:00
|
|
|
|
|
|
|
|
|
// If guild is less than 1 month old don't accept the tweet
|
|
|
|
|
if (interaction.guild.createdAt > date.setMonth(date.getMonth() - 1)) {
|
|
|
|
|
await interaction.editReply({ content: 'The server need to be 1 month old to be able to use this command!' });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset the date for the next check
|
|
|
|
|
date.setTime(Date.now());
|
|
|
|
|
|
|
|
|
|
// If the bot has been in the guild for less than 1 week don't accept the tweet.
|
|
|
|
|
if (interaction.guild.createdAt > date.setDate(date.getDate() - 7)) {
|
|
|
|
|
await interaction.editReply({ content: 'I need to be in this server for a week to be able to use this command!' });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reset the date for the next check
|
|
|
|
|
date.setTime(Date.now());
|
|
|
|
|
|
2022-08-14 22:28:37 +02:00
|
|
|
|
// If account is less than 6 months old don't accept the tweet ( alt prevention )
|
|
|
|
|
if (interaction.user.createdAt > date.setMonth(date.getMonth() - 6)) {
|
|
|
|
|
await interaction.editReply({ content: 'Your account is too new to be able to use this command!' });
|
2022-08-15 15:14:03 +02:00
|
|
|
|
return;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-15 19:32:35 +02:00
|
|
|
|
// Reset the date for the next check
|
2022-08-27 17:40:10 +02:00
|
|
|
|
date.setTime(Date.now());
|
|
|
|
|
|
2022-08-14 22:28:37 +02:00
|
|
|
|
// If account is less than 1 year old don't accept attachment
|
|
|
|
|
if (attachment && interaction.user.createdAt > date.setFullYear(date.getFullYear() - 1)) {
|
|
|
|
|
await interaction.editReply({ content: 'Your account need to be 1 year or older to be able to send attachment!' });
|
2022-08-15 15:14:03 +02:00
|
|
|
|
return;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tweet) {
|
2023-04-15 19:32:35 +02:00
|
|
|
|
// remove zero width space
|
2022-08-14 22:28:37 +02:00
|
|
|
|
tweet = tweet.replace('', '');
|
2023-04-15 19:32:35 +02:00
|
|
|
|
// This should only happen if someone tweets a zero width space
|
|
|
|
|
if (tweet.length === 0) {
|
|
|
|
|
return interaction.reply({ content: 'Uh oh! You are missing any content for me to tweet!', ephemeral: true });
|
|
|
|
|
}
|
2022-08-14 22:28:37 +02:00
|
|
|
|
|
2023-04-14 04:24:46 +02:00
|
|
|
|
wordToCensor.forEach(async word => {
|
|
|
|
|
if (tweet.toLowerCase().includes(word.toLowerCase())) {
|
|
|
|
|
const body = { type:'tweet', uid: interaction.user.id, reason: 'Automatic ban from banned word.' };
|
|
|
|
|
Blacklists.create(body);
|
|
|
|
|
|
|
|
|
|
await interaction.editReply({ content: 'Sike, you just posted cringe! Enjoy the blacklist :)' });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-08-14 22:28:37 +02:00
|
|
|
|
// Detect banned word (Blacklist the user directly)
|
2023-04-14 04:24:46 +02:00
|
|
|
|
/* No worky (I don't remember what the fuck I wrote here)
|
2022-09-10 09:37:06 +02:00
|
|
|
|
if (wordToCensor.includes(tweet) || wordToCensor.includes(tweet.substring(0, tweet.length - 1)) || wordToCensor.includes(tweet.substring(1, tweet.length))) {
|
2022-08-14 22:28:37 +02:00
|
|
|
|
const body = { type:'tweet', uid: interaction.user.id, reason: 'Automatic ban from banned word.' };
|
|
|
|
|
Blacklists.create(body);
|
|
|
|
|
|
|
|
|
|
await interaction.editReply({ content: 'Sike, you just posted cringe! Enjoy the blacklist :)' });
|
2022-08-15 15:14:03 +02:00
|
|
|
|
return;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
2023-04-14 04:24:46 +02:00
|
|
|
|
*/
|
2022-08-14 22:28:37 +02:00
|
|
|
|
|
|
|
|
|
// Very simple link detection
|
|
|
|
|
if (new RegExp('([a-zA-Z0-9]+://)?([a-zA-Z0-9_]+:[a-zA-Z0-9_]+@)?([a-zA-Z0-9.-]+\\.[A-Za-z]{2,4})(:[0-9]+)?(/.*)?').test(tweet) && !tweet.includes('twitter.com')) {
|
2022-08-15 15:14:03 +02:00
|
|
|
|
await interaction.editReply({ content: 'You may not tweet links outside of twitter.com' });
|
|
|
|
|
return;
|
|
|
|
|
}
|
2022-08-14 22:28:37 +02:00
|
|
|
|
// Do not allow discord invites
|
|
|
|
|
if (tweet.includes('discord.gg') || tweet.includes('discord.com/invite/')) {
|
2022-08-15 15:14:03 +02:00
|
|
|
|
await interaction.editReply({ content: 'No discord invite allowed.' });
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-14 22:28:37 +02:00
|
|
|
|
|
2023-04-14 04:24:46 +02:00
|
|
|
|
|
2023-06-04 19:02:30 +02:00
|
|
|
|
const userClient = new TwitterApi({
|
|
|
|
|
appKey: twiConsumer,
|
|
|
|
|
appSecret: twiConsumerSecret,
|
|
|
|
|
accessToken: twiToken,
|
|
|
|
|
accessSecret: twiTokenSecret,
|
2022-08-14 22:28:37 +02:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Make sure there is an attachment and if its an image
|
|
|
|
|
if (attachment) {
|
|
|
|
|
if (attachment.name.toLowerCase().endsWith('.jpg') || attachment.name.toLowerCase().endsWith('.png') || attachment.name.toLowerCase().endsWith('.gif')) {
|
2023-04-04 18:06:05 +02:00
|
|
|
|
const streamPipeline = util.promisify(stream.pipeline);
|
|
|
|
|
const res = await fetch(attachment.url);
|
|
|
|
|
if (!res.ok) return interaction.editReply('An error has occured while trying to download your image.');
|
|
|
|
|
await streamPipeline(res.body, fs.createWriteStream(`${os.tmpdir()}/${attachment.name}`));
|
|
|
|
|
|
|
|
|
|
const file = fs.statSync(`${os.tmpdir()}/${attachment.name}`);
|
|
|
|
|
const fileSize = file.size / 1000000.0;
|
|
|
|
|
|
|
|
|
|
if ((attachment.name.toLowerCase().endsWith('.jpg') || attachment.name.toLowerCase().endsWith('.png')) && fileSize > 5) {
|
|
|
|
|
return interaction.editReply({ content: 'Images can\'t be larger than 5 MB!' });
|
|
|
|
|
}
|
|
|
|
|
else if (attachment.name.toLowerCase().endsWith('.gif') && fileSize > 15) {
|
|
|
|
|
return interaction.editReply({ content: 'Gifs can\'t be larger than 15 MB!' });
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 19:02:30 +02:00
|
|
|
|
const image = await userClient.v1.uploadMedia(`${os.tmpdir()}/${attachment.name}`);
|
|
|
|
|
Tweet(image);
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
await interaction.editReply({ content: 'File type not supported, you can only send jpg/png/gif' });
|
2022-08-15 15:14:03 +02:00
|
|
|
|
return;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Tweet();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (err) {
|
|
|
|
|
console.error(err);
|
|
|
|
|
await interaction.editReply({ content: 'Oh no, an error has occurred :(' });
|
2022-08-15 15:14:03 +02:00
|
|
|
|
return;
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 19:02:30 +02:00
|
|
|
|
async function Tweet(img) {
|
|
|
|
|
let options = null;
|
|
|
|
|
if (img) {
|
|
|
|
|
options = { media: { media_ids: new Array(img) } };
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
2023-06-04 19:02:30 +02:00
|
|
|
|
const tweeted = await userClient.v2.tweet(tweet, options);
|
|
|
|
|
|
|
|
|
|
const tweetid = tweeted.data.id;
|
|
|
|
|
const FunnyWords = ['oppaGangnamStyle', '69', '420', 'cum', 'funnyMan', 'GUCCISmartToilet', 'TwitterForClowns', 'fart', 'ok', 'hi', 'howAreYou', 'WhatsNinePlusTen', '21'];
|
2023-12-26 16:39:42 +01:00
|
|
|
|
const TweetLink = `https://vxtwitter.com/${FunnyWords[Math.floor((Math.random() * FunnyWords.length))]}/status/${tweetid}`;
|
2023-06-04 19:02:30 +02:00
|
|
|
|
|
|
|
|
|
let channel = await client.channels.resolve(twiChannel);
|
|
|
|
|
channel.send(TweetLink);
|
|
|
|
|
|
|
|
|
|
const Embed = new EmbedBuilder()
|
|
|
|
|
.setAuthor({ name: interaction.user.username, iconURL: interaction.user.displayAvatarURL() })
|
|
|
|
|
.setDescription(tweet ? tweet : 'No content.')
|
|
|
|
|
.addFields(
|
|
|
|
|
{ name: 'Link', value: TweetLink, inline: true },
|
|
|
|
|
{ name: 'Tweet ID', value: tweetid, inline: true },
|
|
|
|
|
{ name: 'Channel ID', value: interaction.channel.id, inline: true },
|
|
|
|
|
{ name: 'Message ID', value: interaction.id, inline: true },
|
|
|
|
|
{ name: 'Author', value: `${interaction.user.username} (${interaction.user.id})`, inline: true },
|
|
|
|
|
)
|
|
|
|
|
.setTimestamp();
|
|
|
|
|
|
|
|
|
|
if (interaction.guild) {
|
|
|
|
|
Embed.addFields(
|
|
|
|
|
{ name: 'Guild', value: `${interaction.guild.name} (${interaction.guild.id})`, inline: true },
|
|
|
|
|
{ name: 'message link', value: `https://discord.com/channels/${interaction.guild.id}/${interaction.channel.id}/${interaction.id}`, inline: true },
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
Embed.addFields({ name: 'message link', value: `https://discord.com/channels/@me/${interaction.channel.id}/${interaction.id}` });
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 19:02:30 +02:00
|
|
|
|
if (attachment) Embed.setImage(attachment.url);
|
2022-08-14 22:28:37 +02:00
|
|
|
|
|
2023-06-04 19:02:30 +02:00
|
|
|
|
channel = await client.channels.resolve(twiLogChannel);
|
|
|
|
|
channel.send({ embeds: [Embed] });
|
|
|
|
|
return interaction.editReply({ content: `Go see ur epic tweet ${TweetLink}` });
|
2022-08-14 22:28:37 +02:00
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|