Skip to content

Commit

Permalink
Merge pull request #803 from Bacon-Fixation/Twitch-freatures-for-Turb…
Browse files Browse the repository at this point in the history
…o-Rewrite

Twitch Features for Turbo Rewrite
  • Loading branch information
galnir authored Nov 23, 2023
2 parents fa05fd3 + 3cbccda commit cb023be
Show file tree
Hide file tree
Showing 15 changed files with 1,564 additions and 30 deletions.
2 changes: 1 addition & 1 deletion apps/bot/src/commands/music/play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export class PlayCommand extends Command {

const voiceChannel = (interaction.member as GuildMember).voice.channel;

// edge case - someome initiated the command but left the voice channel
// edge case - someone initiated the command but left the voice channel
if (!voiceChannel) {
return interaction.followUp({
content: ':x: You need to be in a voice channel to use this command!'
Expand Down
183 changes: 183 additions & 0 deletions apps/bot/src/commands/twitch/add-streamer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { MessageChannel } from '../../lib/structures/ExtendedClient';
import { ApplyOptions } from '@sapphire/decorators';
import { Command, CommandOptions, container } from '@sapphire/framework';
import type { GuildChannel } from 'discord.js';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
import { notify } from '../../lib/twitch/notifyChannels';
import { trpcNode } from '../../trpc';

@ApplyOptions<CommandOptions>({
name: 'add-streamer',
description: 'Add a Stream alert from your favorite Twitch streamer',
requiredUserPermissions: 'ModerateMembers',
preconditions: ['GuildOnly', 'isCommandDisabled']
})
export class AddStreamerCommand extends Command {
public override async chatInputRun(
interaction: Command.ChatInputCommandInteraction
) {
const streamerName = interaction.options.getString('streamer-name', true);
const channelData = interaction.options.getChannel('channel-name', true);
const { client } = container;

let isError = false;
let user;
try {
user = await client.twitch.api.getUser({
login: streamerName,
token: client.twitch.auth.access_token
});
} catch (error: any) {
isError = true;
if (error.status == 400) {
return await interaction.reply({
content: `:x: "${streamerName}" was Invalid, Please try again.`
});
}
if (error.status === 401) {
return await interaction.reply({
content: `:x: You are not authorized to use this command.`
});
}
if (error.status == 429) {
return await interaction.reply({
content: ':x: Rate Limit exceeded. Please try again in a few minutes.'
});
}
if (error.status == 500) {
return await interaction.reply({
content: `:x: Twitch service's are currently unavailable. Please try again later.`
});
} else {
return await interaction.reply({
content: `:x: Something went wrong.`
});
}
}

if (isError) return;
if (!user)
return await interaction.reply({
content: `:x: ${streamerName} was not Found`
});
if (!isTextBasedChannel(channelData as GuildChannel))
return await interaction.reply({
content: `:x: Can't send messages to ${channelData.name}`
});

const guildDB = await trpcNode.guild.getGuild.query({
id: interaction.guild!.id
});

if (!guildDB.guild) {
return await interaction.reply({
content: `:x: Something went wrong.`
});
}

// check if streamer is already on notify list
if (guildDB?.guild.notifyList.includes(user.id))
return await interaction.reply({
content: `:x: ${user.display_name} is already on your Notification list`
});

// make sure channel is not already on notify list
for (const twitchChannel in client.twitch.notifyList) {
for (const channelToMsg of client.twitch.notifyList[twitchChannel]
.sendTo) {
const query = client.channels.cache.get(channelToMsg) as MessageChannel;
if (query)
if (query.guild.id == interaction.guild?.id) {
if (twitchChannel == user.id)
return await interaction.reply({
content: `:x: **${user.display_name}** is already has a notification in **#${query.name}**`
});
}
}
}
// make sure no one else is already sending alerts about this streamer
if (client.twitch.notifyList[user.id]?.sendTo.includes(channelData.id))
return await interaction.reply({
content: `:x: **${user.display_name}** is already messaging ${channelData.name}`
});

let channelArray;
if (client.twitch.notifyList[user.id])
channelArray = [
...client.twitch.notifyList[user.id].sendTo,
...[channelData.id]
];
else channelArray = [channelData.id];

// add notification to twitch object on client
client.twitch.notifyList[user.id]
? (client.twitch.notifyList[user.id].sendTo = channelArray)
: (client.twitch.notifyList[user.id] = {
sendTo: [channelData.id],
live: false,
logo: user.profile_image_url,
messageSent: false,
messageHandler: {}
});

// add notification to database
await trpcNode.twitch.create.mutate({
userId: user.id,
userImage: user.profile_image_url,
channelId: channelData.id,
sendTo: client.twitch.notifyList[user.id].sendTo
});

// add notification to guild on database
const concatedArray = guildDB.guild.notifyList.concat([user.id]);

const guild = interaction.guild!;

await trpcNode.twitch.createViaTwitchNotification.mutate({
name: guild.name,
guildId: guild.id,
notifyList: concatedArray,
ownerId: guild.ownerId,
userId: interaction.user.id
});

await interaction.reply({
content: `**${user.display_name}** Stream Notification will be sent to **#${channelData.name}**`
});
const newQuery: string[] = [];
// pickup newly added entries
for (const key in client.twitch.notifyList) {
newQuery.push(key);
}
await notify(newQuery);
return;
}

public override registerApplicationCommands(
registry: Command.Registry
): void {
if (!process.env.TWITCH_CLIENT_ID || !process.env.TWITCH_CLIENT_SECRET) {
return;
}

registry.registerChatInputCommand(builder =>
builder
.setName(this.name)
.setDescription(this.description)
.addStringOption(option =>
option
.setName('streamer-name')
.setDescription('What is the name of the Twitch streamer?')
.setRequired(true)
)
.addChannelOption(option =>
option
.setName('channel-name')
.setDescription(
'What is the name of the Channel you would like the alert to be sent to?'
)
.setRequired(true)
)
);
}
}
149 changes: 149 additions & 0 deletions apps/bot/src/commands/twitch/remove-streamer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { ApplyOptions } from '@sapphire/decorators';
import { Command, CommandOptions, container } from '@sapphire/framework';
import type { GuildChannel } from 'discord.js';
import { isTextBasedChannel } from '@sapphire/discord.js-utilities';
import { trpcNode } from '../../trpc';

@ApplyOptions<CommandOptions>({
name: 'remove-streamer',
description: 'Add a Stream alert from your favorite Twitch streamer',
requiredUserPermissions: 'ModerateMembers',
preconditions: ['GuildOnly', 'isCommandDisabled']
})
export class RemoveStreamerCommand extends Command {
public override async chatInputRun(
interaction: Command.ChatInputCommandInteraction
) {
const streamerName = interaction.options.getString('streamer-name', true);
const channelData = interaction.options.getChannel('channel-name', true);
const { client } = container;

let user: any;
try {
user = await client.twitch.api.getUser({
login: streamerName,
token: client.twitch.auth.access_token
});
} catch (error: any) {
if (error.status == 400) {
return await interaction.reply({
content: `:x: "${streamerName}" was Invalid, Please try again.`
});
}
if (error.status == 429) {
return await interaction.reply({
content: ':x: Rate Limit exceeded. Please try again in a few minutes.'
});
}
if (error.status == 500) {
return await interaction.reply({
content: `:x: Twitch service's are currently unavailable. Please try again later.`
});
} else {
return await interaction.reply({
content: `:x: Something went wrong.`
});
}
}

if (!user)
return await interaction.reply({
content: `:x: ${streamerName} was not Found`
});
if (!isTextBasedChannel(channelData as GuildChannel))
return await interaction.reply({
content: `:x: Cant sent messages to ${channelData.name}`
});

const guildDB = await trpcNode.guild.getGuild.query({
id: interaction.guild!.id
});

const notifyDB = await trpcNode.twitch.findUserById.query({
id: user.id
});

if (!guildDB.guild || !guildDB.guild.notifyList.includes(user.id))
return await interaction.reply({
content: `:x: **${user.display_name}** is not in your Notification list`
});

if (!notifyDB || !notifyDB.notification)
return await interaction.reply({
content: `:x: **${user.display_name}** was not found in Database`
});

let found = false;
notifyDB.notification.channelIds.forEach(channel => {
if (channel == channelData.id) found = true;
});
if (found === false)
return await interaction.reply({
content: `:x: **${user.display_name}** is not assigned to **${channelData}**`
});

const filteredTwitchIds: string[] = guildDB.guild.notifyList.filter(
element => {
return element !== user.id;
}
);

await trpcNode.twitch.updateTwitchNotifications.mutate({
guildId: interaction.guild!.id,
notifyList: filteredTwitchIds
});

const filteredChannelIds: string[] =
notifyDB.notification.channelIds.filter(element => {
return element !== channelData.id;
});

if (filteredChannelIds.length == 0) {
await trpcNode.twitch.delete.mutate({
userId: user.id
});
delete client.twitch.notifyList[user.id];
} else {
await trpcNode.twitch.updateNotification.mutate({
userId: user.id,
channelIds: filteredChannelIds
});

client.twitch.notifyList[user.id].sendTo = filteredChannelIds;
}

await interaction.reply({
content: `**${user.display_name}** Stream Notification will no longer be sent to **#${channelData.name}**`
});

return;
}

public override registerApplicationCommands(
registry: Command.Registry
): void {
if (!process.env.TWITCH_CLIENT_ID || !process.env.TWITCH_CLIENT_SECRET) {
return;
}

registry.registerChatInputCommand(builder =>
builder
.setName(this.name)
.setDescription(this.description)
.addStringOption(option =>
option
.setName('streamer-name')
.setDescription('What is the name of the Twitch streamer?')
.setRequired(true)
)
.addChannelOption(option =>
option
.setName('channel-name')
.setDescription(
'What is the name of the Channel you would like the Alert to be removed from?'
)
.setRequired(true)
)
);
}
}
Loading

0 comments on commit cb023be

Please sign in to comment.