216 lines
5.1 KiB
TypeScript
216 lines
5.1 KiB
TypeScript
import { ApplyOptions } from '@sapphire/decorators';
|
|
import { Command, CommandOptions } from '@sapphire/framework';
|
|
import {
|
|
ColorResolvable,
|
|
StringSelectMenuBuilder,
|
|
ComponentType
|
|
} from 'discord.js';
|
|
import { PaginatedMessage } from '@sapphire/discord.js-utilities';
|
|
import axios from 'axios';
|
|
import Logger from '../../lib/logger';
|
|
|
|
@ApplyOptions<CommandOptions>({
|
|
name: 'reddit',
|
|
description: 'Get posts from reddit by specifying a subreddit',
|
|
preconditions: ['GuildOnly', 'isCommandDisabled']
|
|
})
|
|
export class RedditCommand extends Command {
|
|
public override registerApplicationCommands(
|
|
registry: Command.Registry
|
|
): void {
|
|
registry.registerChatInputCommand(builder =>
|
|
builder
|
|
.setName(this.name)
|
|
.setDescription(this.description)
|
|
.addStringOption(option =>
|
|
option
|
|
.setName('subreddit')
|
|
.setDescription('Subreddit name')
|
|
.setRequired(true)
|
|
)
|
|
.addStringOption(option =>
|
|
option
|
|
.setName('sort')
|
|
.setDescription(
|
|
'What posts do you want to see? Select from best/hot/top/new/controversial/rising'
|
|
)
|
|
.setRequired(true)
|
|
.addChoices(
|
|
{
|
|
name: 'Best',
|
|
value: 'best'
|
|
},
|
|
{
|
|
name: 'Hot',
|
|
value: 'hot'
|
|
},
|
|
{
|
|
name: 'New',
|
|
value: 'new'
|
|
},
|
|
{
|
|
name: 'Top',
|
|
value: 'top'
|
|
},
|
|
{
|
|
name: 'Controversial',
|
|
value: 'controversial'
|
|
},
|
|
{
|
|
name: 'Rising',
|
|
value: 'rising'
|
|
}
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
public override async chatInputRun(
|
|
interaction: Command.ChatInputCommandInteraction
|
|
) {
|
|
await interaction.deferReply();
|
|
const channel = interaction.channel;
|
|
if (!channel) return await interaction.reply('Something went wrong :('); // type guard
|
|
const subreddit = interaction.options.getString('subreddit', true);
|
|
const sort = interaction.options.getString('sort', true);
|
|
|
|
if (['controversial', 'top'].some(val => val === sort)) {
|
|
const row = new StringSelectMenuBuilder()
|
|
.setCustomId('top_or_controversial')
|
|
.setPlaceholder('Please select an option')
|
|
.addOptions(optionsArray);
|
|
|
|
const menu = await channel.send({
|
|
content: `:loud_sound: Do you want to get the ${sort} posts from past hour/week/month/year or all?`,
|
|
components: [
|
|
{
|
|
type: ComponentType.ActionRow,
|
|
|
|
components: [row]
|
|
}
|
|
]
|
|
});
|
|
|
|
const collector = menu.createMessageComponentCollector({
|
|
componentType: ComponentType.StringSelect,
|
|
time: 30000 // 30 sec
|
|
});
|
|
|
|
collector.on('end', () => {
|
|
if (menu) menu.delete().catch(Logger.error);
|
|
});
|
|
|
|
collector.on('collect', async i => {
|
|
if (i.user.id !== interaction.user.id) {
|
|
i.reply({
|
|
content: 'This element is not for you!',
|
|
ephemeral: true
|
|
});
|
|
return;
|
|
} else {
|
|
collector.stop();
|
|
const timeFilter = i.values[0];
|
|
this.fetchFromReddit(interaction, subreddit, sort, timeFilter);
|
|
return;
|
|
}
|
|
});
|
|
} else {
|
|
this.fetchFromReddit(interaction, subreddit, sort);
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
private async fetchFromReddit(
|
|
interaction: Command.ChatInputCommandInteraction,
|
|
subreddit: string,
|
|
sort: string,
|
|
timeFilter = 'day'
|
|
) {
|
|
try {
|
|
var data = await this.getData(subreddit, sort, timeFilter);
|
|
} catch (error: any) {
|
|
return interaction.followUp(error);
|
|
}
|
|
|
|
// interaction.followUp('Fetching data from reddit');
|
|
|
|
const paginatedEmbed = new PaginatedMessage();
|
|
for (let i = 1; i <= data.children.length; i++) {
|
|
let color: ColorResolvable = 'Orange';
|
|
let redditPost = data.children[i - 1];
|
|
|
|
if (redditPost.data.title.length > 255) {
|
|
redditPost.data.title = redditPost.data.title.substring(0, 252) + '...'; // max title length is 256
|
|
}
|
|
|
|
if (redditPost.data.selftext.length > 1024) {
|
|
redditPost.data.selftext =
|
|
redditPost.data.selftext.substring(0, 1024) +
|
|
`[Read More...](https://www.reddit.com${redditPost.data.permalink})`;
|
|
}
|
|
|
|
if (redditPost.data.over_18) color = 'Red'; // red - nsfw
|
|
|
|
paginatedEmbed.addPageEmbed(embed =>
|
|
embed
|
|
.setColor(color)
|
|
.setTitle(redditPost.data.title)
|
|
.setURL(`https://www.reddit.com${redditPost.data.permalink}`)
|
|
.setDescription(
|
|
`${
|
|
redditPost.data.over_18 ? '' : redditPost.data.selftext + '\n\n'
|
|
}Upvotes: ${redditPost.data.score} :thumbsup: `
|
|
)
|
|
.setAuthor({ name: redditPost.data.author })
|
|
);
|
|
}
|
|
|
|
return paginatedEmbed.run(interaction);
|
|
}
|
|
|
|
private getData(
|
|
subreddit: string,
|
|
sort: string,
|
|
timeFilter: string
|
|
): Promise<any> {
|
|
return new Promise(async function (resolve, reject) {
|
|
const response = await axios.get(
|
|
`https://www.reddit.com/r/${subreddit}/${sort}/.json?limit=10&t=${
|
|
timeFilter ? timeFilter : 'day'
|
|
}`
|
|
);
|
|
const data = response.data.data;
|
|
if (!data) {
|
|
reject(`**${subreddit}** is a private subreddit!`);
|
|
} else if (!data.children.length) {
|
|
reject('Please provide a valid subreddit name!');
|
|
}
|
|
resolve(data);
|
|
});
|
|
}
|
|
}
|
|
|
|
const optionsArray = [
|
|
{
|
|
label: 'hour',
|
|
value: 'hour'
|
|
},
|
|
{
|
|
label: 'week',
|
|
value: 'week'
|
|
},
|
|
{
|
|
label: 'month',
|
|
value: 'month'
|
|
},
|
|
{
|
|
label: 'year',
|
|
value: 'year'
|
|
},
|
|
{
|
|
label: 'all',
|
|
value: 'all'
|
|
}
|
|
];
|