Skip to content

Commit 94c227d

Browse files
committed
feat(bot): fully implement dm tracking
1 parent 3836aca commit 94c227d

9 files changed

Lines changed: 101 additions & 59 deletions

File tree

.github/dependabot.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1-
# Moving back to npm for package management rather than bun
2-
# because wow dependabot is so broken for it 😭
31
# TODO: Labels on package updates after project restructure
42

53
version: 2
64
updates:
7-
- package-ecosystem: "npm"
5+
- package-ecosystem: "bun"
86
directory: "/"
97
schedule:
108
interval: "weekly"
119
target-branch: "dev"
1210

13-
- package-ecosystem: "npm"
11+
- package-ecosystem: "bun"
1412
directory: "/web"
1513
schedule:
1614
interval: "weekly"

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ target/
1111
*.sql
1212
dbtests.ts
1313
perftesting.ts
14-
drizzle/
14+
drizzle/
15+
fetchTest.ts

README.md

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,17 +96,26 @@ These guidelines ensure predictable behavior and simplify error handling across
9696
> [!NOTE]
9797
> WIP update!
9898
99-
### Bot
99+
### Fixes
100100

101101
- Fixed the double notification bug
102+
103+
### Changes
104+
102105
- Moved to Postgres as our database engine
106+
107+
### Features
108+
103109
- Improved flow of `/track` command
104110
- Autocomplete for YouTube
105111
- Filter by videos, shorts and streams for YouTube!
112+
- `/tracked` is now improved and is an interactive embed!
113+
- Can now use search/autocomplete for `/track` for both YouTube and Twitch
106114

107-
### API
115+
### Known Issues
108116

109-
### Site
117+
- Twitch channel username doesn't show up in `/track`
118+
- Unable to subscribe to updates via the bot
110119

111120
## V1
112121

@@ -115,7 +124,7 @@ These guidelines ensure predictable behavior and simplify error handling across
115124
- Added a new command! `/tracked` ([#50](https://github.com/GalvinPython/feedr/issues/50))
116125
- See all the tracked channels in your server
117126
- The channel you ran the command in will appear first as there is no option to only see the current channel for now
118-
- Locale improvments ([#43](https://github.com/GalvinPython/feedr/issues/43))
127+
- Locale improvements ([#43](https://github.com/GalvinPython/feedr/issues/43))
119128

120129
### 1.3.0
121130

bun.lock

Lines changed: 7 additions & 3 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
@@ -4,7 +4,7 @@
44
"type": "module",
55
"version": "2.0.0-dev",
66
"devDependencies": {
7-
"@types/bun": "1.2.10",
7+
"@types/bun": "1.2.21",
88
"@types/pg": "^8.11.14",
99
"@typescript-eslint/eslint-plugin": "8.11.0",
1010
"@typescript-eslint/parser": "8.11.0",

src/commands.ts

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import search from "./utils/youtube/search";
3333
import {
3434
checkIfGuildIsTrackingUserAlready,
3535
discordAddGuildTrackingUser,
36+
discordAddNewGuild,
37+
discordCheckIfDmChannelExists,
3638
discordGetAllTrackedInGuild,
3739
discordRemoveGuildTrackingChannel,
3840
} from "./db/discord";
@@ -273,6 +275,8 @@ const commands: Record<string, Command> = {
273275
contexts: [0, 1],
274276
},
275277
execute: async (interaction: CommandInteraction) => {
278+
const isDm = !interaction.inGuild();
279+
276280
// Get the YouTube Channel ID
277281
const targetPlatform = (
278282
interaction as ChatInputCommandInteraction
@@ -284,7 +288,7 @@ const commands: Record<string, Command> = {
284288
const discordChannelId =
285289
(interaction.options.get("updates_channel")?.value as string) ??
286290
interaction.channelId;
287-
const guildId = interaction.guildId;
291+
const guildId = isDm ? discordChannelId : interaction.guildId;
288292

289293
// Log the autocomplete value
290294
console.log(`Autocomplete value: ${platformUserId}`);
@@ -316,33 +320,26 @@ const commands: Record<string, Command> = {
316320
return;
317321
}
318322

319-
// TODO: Enable DMs :)
320-
const isDm = interaction.channel?.isDMBased();
323+
console.log(interaction.channelId);
321324

322-
if (!guildId || isDm || isDm === undefined) {
323-
await interaction.reply({
324-
flags: MessageFlags.Ephemeral,
325-
content:
326-
"This command is not supported in DMs currently!\nNot a DM? Then the bot failed to get the guild info",
327-
});
328-
329-
return;
330-
}
325+
if (isDm) console.log("DM");
331326

332327
// TODO: Embed
333328
// Check the permissions of the user
334-
if (
335-
!interaction.memberPermissions?.has(
336-
PermissionFlagsBits.ManageChannels,
337-
)
338-
) {
339-
await interaction.reply({
340-
flags: MessageFlags.Ephemeral,
341-
content:
342-
"You do not have the permission to manage channels!",
343-
});
329+
if (!isDm) {
330+
if (
331+
!interaction.memberPermissions?.has(
332+
PermissionFlagsBits.ManageChannels,
333+
)
334+
) {
335+
await interaction.reply({
336+
flags: MessageFlags.Ephemeral,
337+
content:
338+
"You do not have the permission to manage channels!",
339+
});
344340

345-
return;
341+
return;
342+
}
346343
}
347344

348345
// TODO: Embed
@@ -397,15 +394,30 @@ const commands: Record<string, Command> = {
397394

398395
return;
399396
}
397+
} else if (isDm) {
398+
// DM channels don't need permission checks
400399
} else {
401400
await interaction.reply({
402401
flags: MessageFlags.Ephemeral,
403-
content: "The target channel is not a text channel!",
402+
content: `The target channel is not a text channel! ${isDm}`,
404403
});
405404

406405
return;
407406
}
408407

408+
// Before attempting to add the subscription, if it's a DM, check if it's already in the database. If not add it
409+
if (isDm) {
410+
console.log("CHECKING DM");
411+
const data = (
412+
await discordCheckIfDmChannelExists(discordChannelId)
413+
).data;
414+
415+
if (!data) {
416+
console.log("ADDING DM");
417+
await discordAddNewGuild(discordChannelId, true);
418+
}
419+
}
420+
409421
switch (targetPlatform) {
410422
case "youtube": {
411423
const contentType = interaction.options.get("content_type")
@@ -571,7 +583,7 @@ const commands: Record<string, Command> = {
571583

572584
await interaction.reply({
573585
flags: MessageFlags.Ephemeral,
574-
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? platformUserId} in ${targetChannel.name}!`,
586+
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? platformUserId} in <#${targetChannel?.id}>!`,
575587
});
576588
} else {
577589
await interaction.reply({
@@ -698,7 +710,7 @@ const commands: Record<string, Command> = {
698710
) {
699711
await interaction.reply({
700712
flags: MessageFlags.Ephemeral,
701-
content: `Started tracking the streamer ${platformUserId} (${platformUserId}) in ${targetChannel.name}!`,
713+
content: `Started tracking the streamer ${platformUserId} (${platformUserId}) in <#${targetChannel?.id}>!`,
702714
});
703715
} else {
704716
await interaction.reply({
@@ -819,24 +831,15 @@ const commands: Record<string, Command> = {
819831
contexts: [0, 1],
820832
},
821833
execute: async (interaction: CommandInteraction) => {
834+
const isDm = !interaction.inGuild();
835+
822836
// Get the YouTube Channel ID
823837
const platformUserId = interaction.options.get("user_id")
824838
?.value as string;
825-
const guildId = interaction.guildId;
826-
827-
// DMs are currently not supported, so throw back an error
828-
if (!guildId || interaction.channel?.isDMBased()) {
829-
await interaction.reply({
830-
flags: MessageFlags.Ephemeral,
831-
content:
832-
"This command is not supported in DMs currently!\nNot a DM? Then an error has occurred :(",
833-
});
834-
835-
return;
836-
}
837839

838840
// Check the permissions of the user
839841
if (
842+
!isDm &&
840843
!interaction.memberPermissions?.has(
841844
PermissionFlagsBits.ManageChannels,
842845
)
@@ -869,7 +872,7 @@ const commands: Record<string, Command> = {
869872
},
870873
autoComplete: async (interaction: AutocompleteInteraction) => {
871874
const trackedChannels = await discordGetAllTrackedInGuild(
872-
interaction.guildId as string,
875+
interaction.guildId ?? (interaction.channelId as string),
873876
);
874877

875878
console.dir(
@@ -916,14 +919,16 @@ const commands: Record<string, Command> = {
916919
contexts: [0, 1],
917920
},
918921
execute: async (interaction: CommandInteraction) => {
919-
const guildId = interaction.guildId;
920-
const channelId = interaction.channelId;
922+
let guildId = interaction.guildId;
923+
924+
const isDm = !interaction.inGuild();
921925

922-
if (!guildId || !channelId) {
926+
if (isDm) guildId = interaction.channelId;
927+
928+
if (!guildId) {
923929
await interaction.reply({
924930
flags: MessageFlags.Ephemeral,
925-
content:
926-
"You are likely in a DM, this command is not supported in DMs!",
931+
content: "An error occurred! Please report",
927932
});
928933

929934
return;

src/db/discord.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,28 @@ export async function discordRemoveGuildFromTracking(
376376
return { success: false, data: [] };
377377
}
378378
}
379+
380+
// Check if the DM channel is already in the "guilds" table
381+
export async function discordCheckIfDmChannelExists(
382+
channelId: string,
383+
): Promise<{ success: boolean; data: (typeof dbDiscordTable.$inferSelect)[] }> {
384+
console.log(`Checking if DM channel exists: ${channelId}`);
385+
386+
try {
387+
const result = await db
388+
.select()
389+
.from(dbDiscordTable)
390+
.where(
391+
and(
392+
eq(dbDiscordTable.guildId, channelId),
393+
eq(dbDiscordTable.isDm, true),
394+
),
395+
);
396+
397+
return { success: true, data: result };
398+
} catch (error) {
399+
console.error("Error checking if DM channel exists:", error);
400+
401+
return { success: false, data: [] };
402+
}
403+
}

src/utils/discord/updateGuildsOnStartup.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export default async function () {
3131

3232
// Find any guilds that are in the database but not in the current guilds
3333
const missingGuilds = data.filter(
34-
(guild) => !currentGuilds.includes(guild.guildId),
34+
(guild) => !currentGuilds.includes(guild.guildId) && !guild.isDm,
3535
);
3636

3737
// Find any guilds that are in the current guilds but not in the database

src/utils/youtube/search.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { config } from "../../config";
21
import type { InnertubeSearchRequest } from "../../types/youtube";
32

3+
import { config } from "../../config";
44
import formatLargeNumber from "../formatLargeNumber";
55

66
export default async function (query: string) {

0 commit comments

Comments
 (0)