Skip to content

Commit 6042203

Browse files
committed
wip: twitch
halfway there
1 parent ecdbadf commit 6042203

File tree

15 files changed

+408
-87
lines changed

15 files changed

+408
-87
lines changed

.env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ MYSQL_USER='YOUR_MYSQL_USER'
1616
MYSQL_PASSWORD='YOUR_MYSQL_PASSWORD'
1717
MYSQL_DATABASE='YOUR_DATABASE_NAME'
1818

19+
# Twitch
20+
TWITCH_CLIENT_ID='YOUR_TWITCH_CLIENT_ID'
21+
TWITCH_CLIENT_SECRET='YOUR_TWITCH_CLIENT_SECRET'
22+
1923
# Configuration
2024
CONFIG_UPDATE_INTERVAL='60'

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Feedr
22
The next best Discord Bot to notify your members about YouTube video uploads!
3-
Feedr checks for new uploads every **15** seconds
3+
Feedr checks for:
4+
* YouTube uploads every **10** seconds
5+
* Twitch streams are live every **2** seconds
46

57
Invite the bot [here](https://discord.com/oauth2/authorize?client_id=1243939861996503171&permissions=274877959232&integration_type=0&scope=applications.commands+bot)
68

@@ -29,6 +31,10 @@ Feedr strives for constant improvement, so here's what will be implemented
2931
* Add Reactions
3032

3133
# Changelog
34+
## 1.2.0
35+
* Added Twitch feed
36+
* `platform` added to both **/track** and **/untrack**
37+
3238
## 1.1.0
3339
* Replies are no longer deferred
3440
* Messages can now be sent in Announcement channels [1.0.3]

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "videonotifier",
33
"module": "src/index.ts",
44
"type": "module",
5-
"version": "1.1.0",
5+
"version": "1.2.0",
66
"devDependencies": {
77
"@types/bun": "1.1.6"
88
},

src/commands.ts

Lines changed: 145 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { heapStats } from 'bun:jsc';
22
import client from '.';
33
import { ChannelType, GuildMember, type CommandInteraction } from 'discord.js';
4-
import checkIfChannelIdIsValid from './utils/checkIfChannelIdIsValid';
5-
import { addNewChannelToTrack, addNewGuildToTrackChannel, checkIfChannelIsAlreadyTracked, checkIfGuildIsTrackingChannelAlready, stopGuildTrackingChannel } from './database';
6-
import getChannelDetails from './utils/getChannelDetails';
4+
import checkIfChannelIdIsValid from './utils/youtube/checkIfChannelIdIsValid';
5+
import { addNewChannelToTrack, addNewGuildToTrackChannel, checkIfChannelIsAlreadyTracked, checkIfGuildIsTrackingChannelAlready, stopGuildTrackingChannel, twitchAddNewChannelToTrack, twitchAddNewGuildToTrackChannel, twitchCheckIfChannelIsAlreadyTracked, twitchCheckIfGuildIsTrackingChannelAlready } from './database';
6+
import getChannelDetails from './utils/youtube/getChannelDetails';
77
import { PermissionFlagsBits } from 'discord-api-types/v8';
8+
import { getStreamerId } from './utils/twitch/getStreamerId';
9+
import { checkIfStreamerIsLive } from './utils/twitch/checkIfStreamerIsLive';
810

911
interface Command {
1012
data: {
@@ -121,54 +123,72 @@ const commands: Record<string, Command> = {
121123
},
122124
track: {
123125
data: {
124-
options: [{
125-
name: 'youtube_channel',
126-
description: 'Enter the YouTube channel ID to track',
127-
type: 3,
128-
required: true,
129-
}, {
130-
name: 'updates_channel',
131-
description: 'Enter the Guild channel to recieve updates in.',
132-
type: 7,
133-
required: true,
134-
}, {
135-
name: 'role',
136-
description: 'Enter the role to mention (optional)',
137-
type: 8,
138-
required: false,
139-
}],
126+
options: [
127+
{
128+
name: 'platform',
129+
description: 'Select a supported platform to track',
130+
type: 3,
131+
required: true,
132+
choices: [
133+
{
134+
name: 'Twitch',
135+
value: 'twitch',
136+
},
137+
{
138+
name: 'YouTube',
139+
value: 'youtube',
140+
},
141+
]
142+
},
143+
{
144+
name: 'user_id',
145+
description: 'Enter the YouTube channel ID or Twitch Streamer to track',
146+
type: 3,
147+
required: true,
148+
}, {
149+
name: 'updates_channel',
150+
description: 'Enter the Guild channel to recieve updates in.',
151+
type: 7,
152+
required: true,
153+
}, {
154+
name: 'role',
155+
description: 'Enter the role to mention (optional)',
156+
type: 8,
157+
required: false,
158+
}],
140159
name: 'track',
141160
description: 'Track a channel to get notified when they upload a video!',
142161
integration_types: [0, 1],
143162
contexts: [0, 1, 2],
144163
},
145164
execute: async (interaction: CommandInteraction) => {
146165
// Get the YouTube Channel ID
147-
const youtubeChannelId = interaction.options.get('youtube_channel')?.value as string;
166+
const targetPlatform = interaction.options.get('platform')?.value as string;
167+
const platformUserId = interaction.options.get('user_id')?.value as string;
148168
const discordChannelId = interaction.options.get('updates_channel')?.value as string;
149169
const guildId = interaction.guildId;
150170

151-
// Check that the channel ID is in a valid format
152-
if (youtubeChannelId.length != 24 || !youtubeChannelId.startsWith('UC')) {
171+
// Checks if the platform is valid ig
172+
if (targetPlatform != 'youtube' && targetPlatform != 'twitch') {
153173
await interaction.reply({
154174
ephemeral: true,
155-
content: 'Invalid YouTube channel ID format!',
175+
content: 'Platform not supported! Please select a platform to track!',
156176
});
157177
return;
158178
}
159179

160180
// DMs are currently not supported, so throw back an error
161181
if (!guildId || interaction.channel?.isDMBased()) {
162-
await interaction.followUp({
182+
await interaction.reply({
163183
ephemeral: true,
164-
content: 'This command is not supported in DMs currently!\nNot a DM? Then an error has occurred :(',
184+
content: 'This command is not supported in DMs currently!\nNot a DM? Then the bot failed to get the guild info',
165185
});
166186
return;
167187
}
168188

169-
// First check the permissions of the user
189+
// Check the permissions of the user
170190
if (!interaction.memberPermissions?.has(PermissionFlagsBits.ManageChannels)) {
171-
await interaction.followUp({
191+
await interaction.reply({
172192
ephemeral: true,
173193
content: 'You do not have the permission to manage channels!',
174194
});
@@ -205,52 +225,109 @@ const commands: Record<string, Command> = {
205225
return;
206226
}
207227

208-
// Check if the channel is valid
209-
if (!await checkIfChannelIdIsValid(youtubeChannelId)) {
210-
await interaction.reply({
211-
ephemeral: true,
212-
content: 'That channel doesn\'t exist!',
213-
});
214-
return;
215-
}
228+
switch (targetPlatform) {
229+
case 'youtube':
230+
// Check that the channel ID is in a valid format
231+
if (platformUserId.length != 24 || !platformUserId.startsWith('UC')) {
232+
await interaction.reply({
233+
ephemeral: true,
234+
content: 'Invalid YouTube channel ID format! Each channel ID should be 24 characters long and start with "UC".',
235+
});
236+
return;
237+
}
216238

217-
// Check if the channel is already being tracked in the guild
218-
if (await checkIfGuildIsTrackingChannelAlready(youtubeChannelId, guildId)) {
219-
await interaction.reply({
220-
ephemeral: true,
221-
content: 'This channel is already being tracked!',
222-
});
223-
return;
224-
}
239+
// Check if the channel is valid
240+
if (!await checkIfChannelIdIsValid(platformUserId)) {
241+
await interaction.reply({
242+
ephemeral: true,
243+
content: 'That channel doesn\'t exist!',
244+
});
245+
return;
246+
}
225247

226-
// Check if the channel is already being tracked globally
227-
if (!await checkIfChannelIsAlreadyTracked(youtubeChannelId)) {
228-
if (!await addNewChannelToTrack(youtubeChannelId)) {
229-
await interaction.reply({
230-
ephemeral: true,
231-
content: 'An error occurred while trying to add the channel to track! This is a new channel being tracked globally, please report this error!',
232-
});
248+
// Check if the channel is already being tracked in the guild
249+
if (await checkIfGuildIsTrackingChannelAlready(platformUserId, guildId)) {
250+
await interaction.reply({
251+
ephemeral: true,
252+
content: 'This channel is already being tracked!',
253+
});
254+
return;
255+
}
256+
257+
// Check if the channel is already being tracked globally
258+
if (!await checkIfChannelIsAlreadyTracked(platformUserId)) {
259+
if (!await addNewChannelToTrack(platformUserId)) {
260+
await interaction.reply({
261+
ephemeral: true,
262+
content: 'An error occurred while trying to add the channel to track! This is a new channel being tracked globally, please report this error!',
263+
});
264+
return;
265+
}
266+
}
267+
268+
// Add the guild to the database
269+
if (await addNewGuildToTrackChannel(guildId, platformUserId, discordChannelId, interaction.options.get('role')?.value as string ?? null)) {
270+
const youtubeChannelInfo = await getChannelDetails(platformUserId)
271+
await interaction.reply({
272+
ephemeral: true,
273+
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? platformUserId} in ${targetChannel.name}!`,
274+
});
275+
} else {
276+
await interaction.reply({
277+
ephemeral: true,
278+
content: 'An error occurred while trying to add the guild to track the channel! Please report this error!',
279+
});
280+
}
233281
return;
234-
}
235-
}
282+
case 'twitch':
283+
// Check if the streamer exists by getting the ID
284+
const streamerId = await getStreamerId(platformUserId);
236285

237-
// Add the guild to the database
238-
if (await addNewGuildToTrackChannel(guildId, youtubeChannelId, discordChannelId, interaction.options.get('role')?.value as string ?? null)) {
239-
const channelIdInfo = await client.channels.fetch(discordChannelId);
240-
if (channelIdInfo && (channelIdInfo.type === ChannelType.GuildText || channelIdInfo.type === ChannelType.GuildAnnouncement)) {
241-
const youtubeChannelInfo = await getChannelDetails(youtubeChannelId)
286+
if (!streamerId) {
287+
await interaction.reply({
288+
ephemeral: true,
289+
content: 'That streamer doesn\'t exist!',
290+
});
291+
return;
292+
}
242293

243-
await interaction.reply({
244-
ephemeral: true,
245-
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? youtubeChannelId} in ${channelIdInfo.name}!`,
246-
});
247-
} else {
248-
await interaction.reply({
249-
ephemeral: true,
250-
content: 'The channel to send updates to is not a text channel! Please make sure to set a text channel!',
251-
});
252-
}
253-
return;
294+
// Check if the channel is already being tracked in the guild
295+
if (await twitchCheckIfGuildIsTrackingChannelAlready(platformUserId, guildId)) {
296+
await interaction.reply({
297+
ephemeral: true,
298+
content: 'This streamer is already being tracked!',
299+
});
300+
return;
301+
}
302+
303+
// Check if the channel is already being tracked globally
304+
if (!await twitchCheckIfChannelIsAlreadyTracked(platformUserId)) {
305+
const isLive = await checkIfStreamerIsLive(streamerId);
306+
if (!await twitchAddNewChannelToTrack(platformUserId, isLive)) {
307+
await interaction.reply({
308+
ephemeral: true,
309+
content: 'An error occurred while trying to add the streamer to track! This is a new streamer being tracked globally, please report this error!',
310+
});
311+
return;
312+
}
313+
}
314+
315+
// Add the guild to the database
316+
if (await twitchAddNewGuildToTrackChannel(guildId, platformUserId, discordChannelId, interaction.options.get('role')?.value as string ?? null)) {
317+
await interaction.reply({
318+
ephemeral: true,
319+
content: `Started tracking the streamer ${platformUserId} in ${targetChannel.name}!`,
320+
});
321+
} else {
322+
await interaction.reply({
323+
ephemeral: true,
324+
content: 'An error occurred while trying to add the guild to track the streamer! Please report this error!',
325+
});
326+
}
327+
return;
328+
default:
329+
console.error('This should never happen');
330+
break;
254331
}
255332
}
256333
},

src/config.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// FILL IN THIS INFORMATION IN .ENV
2-
export const config: { [key: string]: string | number | undefined } = {
3-
updateInterval: process.env?.CONFIG_UPDATE_INTERVAL ? parseInt(process.env?.CONFIG_UPDATE_INTERVAL) * 1000 : undefined,
2+
export const config: { [key: string]: string | number } = {
3+
updateInterval: process.env?.CONFIG_UPDATE_INTERVAL ? parseInt(process.env?.CONFIG_UPDATE_INTERVAL) * 1000 : 60_000,
44
}
55

66
export const env: { [key: string]: string | undefined } = {
@@ -11,4 +11,6 @@ export const env: { [key: string]: string | undefined } = {
1111
mysqlUser: process.env?.MYSQL_USER,
1212
mysqlPassword: process.env?.MYSQL_PASSWORD,
1313
mysqlDatabase: process.env?.MYSQL_DATABASE,
14+
twitchClientId: process.env?.TWITCH_CLIENT_ID,
15+
twitchClientSecret: process.env?.TWITCH_CLIENT_SECRET,
1416
};

0 commit comments

Comments
 (0)