Skip to content

Commit 29c70c5

Browse files
authored
Merge pull request #167 from GalvinPython/feat/dm-notifications
2 parents 0d2e8ee + b7c7ffe commit 29c70c5

12 files changed

Lines changed: 120 additions & 66 deletions

File tree

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ DISCORD_DEV_TOKEN='YOUR_DISCORD_DEV_TOKEN'
88

99
# YouTube API Key
1010
YOUTUBE_API_KEY='YOUR_YOUTUBE_API_KEY'
11+
YOUTUBE_INNERTUBE_PROXY_URL='YOUR_OPTIONAL_YOUTUBE_INNERTUBE_PROXY_URL'
1112

1213
# Twitch
1314
TWITCH_CLIENT_ID='YOUR_TWITCH_CLIENT_ID'

.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: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
ActionRowBuilder,
55
ApplicationCommandOptionType,
66
ApplicationCommandType,
7+
ApplicationIntegrationType,
78
AutocompleteInteraction,
89
ButtonBuilder,
910
ButtonStyle,
@@ -12,6 +13,7 @@ import {
1213
ComponentType,
1314
EmbedBuilder,
1415
GuildMember,
16+
InteractionContextType,
1517
MessageFlags,
1618
type ApplicationCommandOptionData,
1719
type CacheType,
@@ -31,6 +33,8 @@ import search from "./utils/youtube/search";
3133
import {
3234
checkIfGuildIsTrackingUserAlready,
3335
discordAddGuildTrackingUser,
36+
discordAddNewGuild,
37+
discordCheckIfDmChannelExists,
3438
discordGetAllTrackedInGuild,
3539
discordRemoveGuildTrackingChannel,
3640
} from "./db/discord";
@@ -54,8 +58,8 @@ interface Command {
5458
name: string;
5559
description: string;
5660
options?: ApplicationCommandOptionData[];
57-
integration_types?: number[];
58-
contexts?: number[];
61+
integration_types?: ApplicationIntegrationType[];
62+
contexts?: InteractionContextType[];
5963
type?: ApplicationCommandType;
6064
};
6165
execute: (interaction: ChatInputCommandInteraction) => Promise<void>;
@@ -64,6 +68,8 @@ interface Command {
6468
) => Promise<any>;
6569
}
6670

71+
// Context 2: Interaction can be used within Group DMs and DMs other than the app's bot user
72+
// /track, /tracked and /untracked can't be used in these contexts
6773
const commands: Record<string, Command> = {
6874
ping: {
6975
data: {
@@ -76,7 +82,7 @@ const commands: Record<string, Command> = {
7682
execute: async (interaction: CommandInteraction) => {
7783
await interaction
7884
.reply({
79-
ephemeral: false,
85+
flags: MessageFlags.Ephemeral,
8086
content: `Ping: ${interaction.client.ws.ping}ms`,
8187
})
8288
.catch(console.error);
@@ -134,7 +140,7 @@ const commands: Record<string, Command> = {
134140
execute: async (interaction: CommandInteraction) => {
135141
await interaction
136142
.reply({
137-
ephemeral: false,
143+
flags: MessageFlags.Ephemeral,
138144
content: `Uptime: ${(
139145
performance.now() /
140146
(86400 * 1000)
@@ -149,7 +155,7 @@ const commands: Record<string, Command> = {
149155
name: "hmm",
150156
description: "What does this command do?",
151157
integration_types: [0, 1],
152-
contexts: [0, 1],
158+
contexts: [0, 1, 2],
153159
},
154160
execute: async (interaction: CommandInteraction) => {
155161
await interaction.reply({
@@ -173,7 +179,7 @@ const commands: Record<string, Command> = {
173179
Bun.gc(false);
174180
await interaction
175181
.reply({
176-
ephemeral: false,
182+
flags: MessageFlags.Ephemeral,
177183
content: [
178184
`Heap size: ${(heap.heapSize / 1024 / 1024).toFixed(2)} MB / ${(
179185
heap.heapCapacity /
@@ -266,9 +272,11 @@ const commands: Record<string, Command> = {
266272
description:
267273
"Track a channel to get notified when they upload a video!",
268274
integration_types: [0, 1],
269-
contexts: [0, 1, 2],
275+
contexts: [0, 1],
270276
},
271277
execute: async (interaction: CommandInteraction) => {
278+
const isDm = !interaction.inGuild();
279+
272280
// Get the YouTube Channel ID
273281
const targetPlatform = (
274282
interaction as ChatInputCommandInteraction
@@ -280,7 +288,7 @@ const commands: Record<string, Command> = {
280288
const discordChannelId =
281289
(interaction.options.get("updates_channel")?.value as string) ??
282290
interaction.channelId;
283-
const guildId = interaction.guildId;
291+
const guildId = isDm ? discordChannelId : interaction.guildId;
284292

285293
// Log the autocomplete value
286294
console.log(`Autocomplete value: ${platformUserId}`);
@@ -312,33 +320,26 @@ const commands: Record<string, Command> = {
312320
return;
313321
}
314322

315-
// TODO: Enable DMs :)
316-
const isDm = interaction.channel?.isDMBased();
317-
318-
if (!guildId || isDm || isDm === undefined) {
319-
await interaction.reply({
320-
flags: MessageFlags.Ephemeral,
321-
content:
322-
"This command is not supported in DMs currently!\nNot a DM? Then the bot failed to get the guild info",
323-
});
323+
console.log(interaction.channelId);
324324

325-
return;
326-
}
325+
if (isDm) console.log("DM");
327326

328327
// TODO: Embed
329328
// Check the permissions of the user
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-
});
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+
});
340340

341-
return;
341+
return;
342+
}
342343
}
343344

344345
// TODO: Embed
@@ -393,6 +394,8 @@ const commands: Record<string, Command> = {
393394

394395
return;
395396
}
397+
} else if (isDm) {
398+
// DM channels don't need permission checks
396399
} else {
397400
await interaction.reply({
398401
flags: MessageFlags.Ephemeral,
@@ -402,6 +405,17 @@ const commands: Record<string, Command> = {
402405
return;
403406
}
404407

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+
const data = (
411+
await discordCheckIfDmChannelExists(discordChannelId)
412+
).data;
413+
414+
if (!data.length) {
415+
await discordAddNewGuild(discordChannelId, true);
416+
}
417+
}
418+
405419
switch (targetPlatform) {
406420
case "youtube": {
407421
const contentType = interaction.options.get("content_type")
@@ -567,7 +581,7 @@ const commands: Record<string, Command> = {
567581

568582
await interaction.reply({
569583
flags: MessageFlags.Ephemeral,
570-
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? platformUserId} in ${targetChannel.name}!`,
584+
content: `Started tracking the channel ${youtubeChannelInfo?.channelName ?? platformUserId} in <#${targetChannel?.id}>!`,
571585
});
572586
} else {
573587
await interaction.reply({
@@ -694,7 +708,7 @@ const commands: Record<string, Command> = {
694708
) {
695709
await interaction.reply({
696710
flags: MessageFlags.Ephemeral,
697-
content: `Started tracking the streamer ${platformUserId} (${platformUserId}) in ${targetChannel.name}!`,
711+
content: `Started tracking the streamer ${platformUserId} (${platformUserId}) in <#${targetChannel?.id}>!`,
698712
});
699713
} else {
700714
await interaction.reply({
@@ -815,24 +829,15 @@ const commands: Record<string, Command> = {
815829
contexts: [0, 1],
816830
},
817831
execute: async (interaction: CommandInteraction) => {
832+
const isDm = !interaction.inGuild();
833+
818834
// Get the YouTube Channel ID
819835
const platformUserId = interaction.options.get("user_id")
820836
?.value as string;
821-
const guildId = interaction.guildId;
822-
823-
// DMs are currently not supported, so throw back an error
824-
if (!guildId || interaction.channel?.isDMBased()) {
825-
await interaction.reply({
826-
flags: MessageFlags.Ephemeral,
827-
content:
828-
"This command is not supported in DMs currently!\nNot a DM? Then an error has occurred :(",
829-
});
830-
831-
return;
832-
}
833837

834838
// Check the permissions of the user
835839
if (
840+
!isDm &&
836841
!interaction.memberPermissions?.has(
837842
PermissionFlagsBits.ManageChannels,
838843
)
@@ -865,7 +870,7 @@ const commands: Record<string, Command> = {
865870
},
866871
autoComplete: async (interaction: AutocompleteInteraction) => {
867872
const trackedChannels = await discordGetAllTrackedInGuild(
868-
interaction.guildId as string,
873+
interaction.guildId ?? (interaction.channelId as string),
869874
);
870875

871876
console.dir(
@@ -912,14 +917,16 @@ const commands: Record<string, Command> = {
912917
contexts: [0, 1],
913918
},
914919
execute: async (interaction: CommandInteraction) => {
915-
const guildId = interaction.guildId;
916-
const channelId = interaction.channelId;
920+
let guildId = interaction.guildId;
917921

918-
if (!guildId || !channelId) {
922+
const isDm = !interaction.inGuild();
923+
924+
if (isDm) guildId = interaction.channelId;
925+
926+
if (!guildId) {
919927
await interaction.reply({
920928
flags: MessageFlags.Ephemeral,
921-
content:
922-
"You are likely in a DM, this command is not supported in DMs!",
929+
content: "An error occurred! Please report",
923930
});
924931

925932
return;

0 commit comments

Comments
 (0)