Skip to content

Commit 05bb4ca

Browse files
authored
Merge branch 'dev' into feat/site
2 parents 0f4da00 + a14ca30 commit 05bb4ca

19 files changed

+519
-156
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ target/
1010
*.sqlite
1111
*.sqlite3*
1212
*.sql
13-
dbtests.ts
13+
dbtests.ts
14+
perftesting.ts

new.dbml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,10 @@ Table twitch {
6060
}
6161

6262
Table bot_info {
63+
time datetime [not null, default: `now()`]
6364
guilds_total int [not null, default: 0]
6465
channels_tracked int [not null, default: 0]
6566
total_members int [not null, default: 0]
66-
updated_at datetime [not null, default: `now()`]
67-
extended_info_updated_at datetime [not null, default: `now()`]
6867
}
6968

7069
Table bot_info_notifications {

src/commands.ts

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,22 @@ import { PermissionFlagsBits } from "discord-api-types/v8";
1515

1616
import checkIfChannelIdIsValid from "./utils/youtube/checkIfChannelIdIsValid";
1717
import {
18-
addNewChannelToTrack,
1918
addNewGuildToTrackChannel,
20-
checkIfChannelIsAlreadyTracked,
2119
checkIfGuildIsTrackingChannelAlready,
2220
getAllTrackedInGuild,
2321
stopGuildTrackingChannel,
2422
twitchAddNewChannelToTrack,
2523
twitchAddNewGuildToTrackChannel,
2624
twitchCheckIfChannelIsAlreadyTracked,
27-
twitchCheckIfGuildIsTrackingChannelAlready,
2825
twitchStopGuildTrackingChannel,
2926
} from "./utils/database";
3027
import getChannelDetails from "./utils/youtube/getChannelDetails";
3128
import { getStreamerId } from "./utils/twitch/getStreamerId";
3229
import { checkIfStreamerIsLive } from "./utils/twitch/checkIfStreamerIsLive";
30+
import {
31+
checkIfChannelIsAlreadyTracked,
32+
addNewChannelToTrack,
33+
} from "./utils/db/youtube";
3334

3435
import client from ".";
3536

@@ -131,7 +132,8 @@ const commands: Record<string, Command> = {
131132
data: {
132133
options: [],
133134
name: "usage",
134-
description: "Check the heap size and disk usage of the bot!",
135+
description:
136+
"Check the heap size and disk usage of the bot! (Stats for nerds)",
135137
integration_types: [0, 1],
136138
contexts: [0, 1, 2],
137139
},
@@ -316,7 +318,7 @@ const commands: Record<string, Command> = {
316318
}
317319

318320
switch (targetPlatform) {
319-
case "youtube":
321+
case "youtube": {
320322
// Check that the channel ID is in a valid format
321323
if (
322324
platformUserId.length != 24 ||
@@ -341,16 +343,17 @@ const commands: Record<string, Command> = {
341343
return;
342344
}
343345

344-
// Check if the channel is already being tracked in the guild
345-
if (
346+
const trackedChannels =
346347
await checkIfGuildIsTrackingChannelAlready(
347348
platformUserId,
348349
guildId,
349-
)
350-
) {
350+
);
351+
352+
// Check if the channel is already being tracked in the guild
353+
if (trackedChannels.length) {
351354
await interaction.reply({
352355
flags: MessageFlags.Ephemeral,
353-
content: "This channel is already being tracked!",
356+
content: `This channel is already being tracked in ${trackedChannels.map((channel, index) => `${index > 0 && index === trackedChannels.length - 1 ? "and " : ""}<#${channel.guild_channel_id}>`).join(", ")}!`,
354357
});
355358

356359
return;
@@ -397,6 +400,7 @@ const commands: Record<string, Command> = {
397400
}
398401

399402
return;
403+
}
400404
case "twitch": {
401405
// Check if the streamer exists by getting the ID
402406
const streamerId = await getStreamerId(platformUserId);
@@ -410,16 +414,17 @@ const commands: Record<string, Command> = {
410414
return;
411415
}
412416

413-
// Check if the channel is already being tracked in the guild
414-
if (
415-
await twitchCheckIfGuildIsTrackingChannelAlready(
416-
streamerId,
417+
const trackedChannels =
418+
await checkIfGuildIsTrackingChannelAlready(
419+
platformUserId,
417420
guildId,
418-
)
419-
) {
421+
);
422+
423+
// Check if the channel is already being tracked in the guild
424+
if (trackedChannels.length) {
420425
await interaction.reply({
421426
flags: MessageFlags.Ephemeral,
422-
content: "This streamer is already being tracked!",
427+
content: `This channel is already being tracked in ${trackedChannels.map((channel, index) => `${index > 0 && index === trackedChannels.length - 1 ? "and " : ""}<#${channel.guild_channel_id}>`).join(", ")}!`,
423428
});
424429

425430
return;
@@ -622,7 +627,7 @@ const commands: Record<string, Command> = {
622627

623628
// check if the channel is not being tracked in the guild
624629
if (
625-
!(await twitchCheckIfGuildIsTrackingChannelAlready(
630+
!(await checkIfGuildIsTrackingChannelAlready(
626631
streamerId,
627632
guildId,
628633
))

src/index.ts

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,19 @@
22
import fs from "fs/promises";
33
import path from "path";
44

5+
import Bun from "bun";
56
import {
67
Client,
78
GatewayIntentBits,
89
REST,
910
Routes,
1011
type APIApplicationCommand,
1112
} from "discord.js";
12-
import { CronJob } from "cron";
1313

1414
import { env } from "./config.ts";
1515
import commandsMap from "./commands.ts";
1616
import initTables from "./utils/db/init.ts";
1717
import { getTwitchToken } from "./utils/twitch/auth.ts";
18-
import backup from "./utils/backup.ts";
1918

2019
if (!env.discordToken || env.discordToken === "YOUR_DISCORD_TOKEN") {
2120
throw new Error("You MUST provide a discord token in .env!");
@@ -36,15 +35,6 @@ if (
3635
throw new Error("You MUST provide a Twitch client secret in .env!");
3736
}
3837

39-
// Start the cron jobs
40-
await fs.mkdir(path.resolve(process.cwd(), "backups"), { recursive: true });
41-
new CronJob("0 0 * * *", async () => {
42-
await backup(
43-
path.resolve(process.cwd(), "db.sqlite3"),
44-
`./backups/db-${new Date().toISOString().replace(/[:.]/g, "-")}.sqlite3`,
45-
);
46-
}).start();
47-
4838
const client = new Client({
4939
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
5040
});
@@ -90,3 +80,11 @@ await Promise.all(
9080
await import("./events/" + file);
9181
}),
9282
);
83+
84+
// Attempt the garbage collection every hour
85+
setInterval(
86+
() => {
87+
Bun.gc(true);
88+
},
89+
60 * 60 * 1000,
90+
);

src/types/database.d.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// This file contains TypeScript interfaces for the database schema used in the application.
2+
// YouTube Table Interface
13
export interface dbYouTube {
24
youtube_channel_id: string;
35
latest_video_id: string | null;
@@ -9,15 +11,27 @@ export interface dbYouTube {
911
youtube_channel_is_live: boolean;
1012
}
1113

14+
// Twitch Table Interface
1215
export interface dbTwitch {
1316
twitch_channel_id: string;
1417
is_live: boolean;
1518
}
1619

17-
export type dbDiscordTable = {
20+
// Guild YouTube Subscriptions Table Interface
21+
export interface dbDiscordTable {
1822
guild_id: string;
1923
guild_channel_id: string;
2024
guild_platform: string;
2125
platform_user_id: string;
2226
guild_ping_role: null | string;
23-
};
27+
}
28+
29+
// Bot Info Table Interface
30+
export interface dbBotInfo {
31+
locked_row: boolean;
32+
guilds_total: number;
33+
channels_tracked: number;
34+
total_members: number;
35+
updated_at: string;
36+
extended_info_updated_at: string;
37+
}

src/types/innertube.d.ts renamed to src/types/youtube.d.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,106 @@
1+
// This file contains TypeScript interfaces for the YouTube API responses and requests used in the bot.
2+
// YouTube Playlist API Response Interface
3+
export interface YouTubePlaylistResponse {
4+
kind: string;
5+
etag: string;
6+
nextPageToken: string;
7+
items: Array<{
8+
kind: string;
9+
etag: string;
10+
id: string;
11+
snippet: {
12+
publishedAt: string;
13+
channelId: string;
14+
title: string;
15+
description: string;
16+
thumbnails: {
17+
default: {
18+
url: string;
19+
width: number;
20+
height: number;
21+
};
22+
medium: {
23+
url: string;
24+
width: number;
25+
height: number;
26+
};
27+
high: {
28+
url: string;
29+
width: number;
30+
height: number;
31+
};
32+
standard: {
33+
url: string;
34+
width: number;
35+
height: number;
36+
};
37+
maxres: {
38+
url: string;
39+
width: number;
40+
height: number;
41+
};
42+
};
43+
channelTitle: string;
44+
playlistId: string;
45+
position: number;
46+
resourceId: {
47+
kind: string;
48+
videoId: string;
49+
};
50+
videoOwnerChannelTitle: string;
51+
videoOwnerChannelId: string;
52+
};
53+
}>;
54+
pageInfo: {
55+
totalResults: number;
56+
resultsPerPage: number;
57+
};
58+
}
59+
60+
// YouTube Channel API Response Interface
61+
export interface YouTubeChannelResponse {
62+
kind: string;
63+
etag: string;
64+
pageInfo: {
65+
totalResults: number;
66+
resultsPerPage: number;
67+
};
68+
items: Array<{
69+
kind: string;
70+
etag: string;
71+
id: string;
72+
snippet: {
73+
title: string;
74+
description: string;
75+
customUrl: string;
76+
publishedAt: string;
77+
thumbnails: {
78+
default: {
79+
url: string;
80+
width: number;
81+
height: number;
82+
};
83+
medium: {
84+
url: string;
85+
width: number;
86+
height: number;
87+
};
88+
high: {
89+
url: string;
90+
width: number;
91+
height: number;
92+
};
93+
};
94+
localized: {
95+
title: string;
96+
description: string;
97+
};
98+
country: string;
99+
};
100+
}>;
101+
}
102+
103+
// YouTube Innertube Search Request Interface
1104
export interface InnertubeSearchRequest {
2105
contents: {
3106
twoColumnSearchResultsRenderer: {

src/utils/backup.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.

src/utils/cronJobs.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { ActivityType, Guild, PresenceUpdateStatus } from "discord.js";
2+
3+
import client from "..";
4+
5+
import { updateBotInfo } from "./db/botinfo";
6+
7+
export async function cronUpdateBotInfo() {
8+
if (!client?.user) return;
9+
10+
const servers: number = client.guilds.cache.size;
11+
const members: number = client.guilds.cache.reduce(
12+
(acc: number, guild: Guild): number => acc + guild.memberCount,
13+
0,
14+
);
15+
16+
await updateBotInfo(servers, members);
17+
client.user.setPresence({
18+
activities: [
19+
{
20+
name: `Notifying ${servers.toLocaleString()} servers [${members.toLocaleString()} members]`,
21+
type: ActivityType.Custom,
22+
},
23+
],
24+
status: PresenceUpdateStatus.Online,
25+
});
26+
}

0 commit comments

Comments
 (0)