Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TWITCH_CLIENT_SECRET='YOUR_TWITCH_CLIENT_SECRET'
CONFIG_UPDATE_INTERVAL_YOUTUBE='10'
CONFIG_UPDATE_INTERVAL_TWITCH='2'
CONFIG_DISCORD_LOGS_CHANNEL='YOUR_DISCORD_LOGS_CHANNEL'
CONFIG_DISCORD_WAIT_FOR_GUILD_CACHE_TIME='YOUR_TIME_IN_SECONDS'

# Postgres URLs
POSTGRES_URL='postgresql://user:password@server:port/database'
Expand Down
5 changes: 5 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export interface Config {
updateIntervalYouTube: number;
updateIntervalTwitch: number;
databaseUrl: string | undefined;
discordWaitForGuildCacheTime: number;
}

export const config: Config = {
Expand All @@ -16,6 +17,10 @@ export const config: Config = {
databaseUrl: runningInDevMode
? process.env?.POSTGRES_DEV_URL
: process.env?.POSTGRES_URL,
discordWaitForGuildCacheTime: process.env
?.CONFIG_DISCORD_WAIT_FOR_GUILD_CACHE_TIME
? parseInt(process.env?.CONFIG_DISCORD_WAIT_FOR_GUILD_CACHE_TIME) * 1000
: 10_000,
};

interface Env {
Expand Down
44 changes: 44 additions & 0 deletions src/db/discord.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { db } from "./db";
import {
dbGuildYouTubeSubscriptionsTable,
dbGuildTwitchSubscriptionsTable,
dbDiscordTable,
} from "./schema";

export async function checkIfGuildIsTrackingUserAlready(
Expand Down Expand Up @@ -280,3 +281,46 @@ export async function discordRemoveGuildTrackingChannel(
return { success: false, data: [] };
}
}

// Add a new guild to track
export async function discordAddNewGuild(
guildId: string,
): Promise<{ success: boolean; data: [] }> {
console.log(`Adding new guild to track: ${guildId}`);

try {
await db.insert(dbDiscordTable).values({
guildId,
allowedPublicSharing: false,
isInServer: true,
memberCount: 0,
});

return { success: true, data: [] };
} catch (error) {
console.error("Error adding new guild to track:", error);

return { success: false, data: [] };
}
}

// "Remove" a guild from tracking
// Basically just set isInServer to false for archival purposes
export async function discordRemoveGuildFromTracking(
guildId: string,
): Promise<{ success: boolean; data: [] }> {
console.log(`Removing guild from tracking: ${guildId}`);

try {
await db
.update(dbDiscordTable)
.set({ isInServer: false })
.where(eq(dbDiscordTable.guildId, guildId));

return { success: true, data: [] };
} catch (error) {
console.error("Error removing guild from tracking:", error);

return { success: false, data: [] };
}
}
1 change: 1 addition & 0 deletions src/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const dbDiscordTable = pgTable("discord", {
allowedPublicSharing: boolean("allowed_public_sharing").notNull().default(false),
feedrUpdatesChannelId: text("feedr_updates_channel_id"),
isInServer: boolean("is_in_server").notNull().default(true),
memberCount: integer("member_count").notNull().default(0),
});

export const dbBlueskyTable = pgTable("bluesky", {
Expand Down
17 changes: 17 additions & 0 deletions src/events/guildCreate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Events } from "discord.js";

import client from "..";
import { discordAddNewGuild } from "../db/discord";

client.on(Events.GuildCreate, async (guild) => {
console.log(`Joined new guild: ${guild.name} (ID: ${guild.id})`);

// Add the new guild to tracking
const result = await discordAddNewGuild(guild.id);

if (result.success) {
console.log(`Successfully added guild ${guild.id} to tracking.`);
} else {
console.error(`Failed to add guild ${guild.id} to tracking.`);
}
});
17 changes: 17 additions & 0 deletions src/events/guildDelete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Events } from "discord.js";

import client from "..";
import { discordRemoveGuildFromTracking } from "../db/discord";

client.on(Events.GuildDelete, async (guild) => {
console.log(`Left guild: ${guild.name} (ID: ${guild.id})`);

// Remove the guild from tracking
const result = await discordRemoveGuildFromTracking(guild.id);

if (result.success) {
console.log(`Successfully removed guild ${guild.id} from tracking.`);
} else {
console.error(`Failed to remove guild ${guild.id} from tracking.`);
}
});
4 changes: 4 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { env } from "./config.ts";
import commandsMap from "./commands.ts";
import { getTwitchToken } from "./utils/twitch/auth.ts";
import updateGuildsOnStartup from "./utils/discord/updateGuildsOnStartup.ts";

if (!env.discordToken || env.discordToken === "YOUR_DISCORD_TOKEN") {
throw new Error("You MUST provide a discord token in .env!");
Expand Down Expand Up @@ -75,6 +76,9 @@ await Promise.all(
}),
);

// Update the guilds on startup
await updateGuildsOnStartup();

// Attempt the garbage collection every hour
setInterval(
() => {
Expand Down
97 changes: 97 additions & 0 deletions src/utils/discord/updateGuildsOnStartup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Checks for any guilds that may have been added/removed while the bot was offline
import { eq } from "drizzle-orm";

import { dbDiscordTable } from "../../db/schema";
import client from "../..";
import { db } from "../../db/db";
import { config } from "../../config";

export default async function () {
console.log("Checking for guilds to update on startup...");

let currentGuilds: string[] = [];

// Keep checking every 10 seconds until currentGuilds is not empty
while (currentGuilds.length === 0) {
console.log("Waiting for guilds to load...");
currentGuilds = client.guilds.cache.map((guild) => guild.id);
if (currentGuilds.length === 0) {
await new Promise((resolve) =>
setTimeout(resolve, config.discordWaitForGuildCacheTime),
);
}
}

// Get all the guilds from the database
const data = await db.select().from(dbDiscordTable);

console.log(
`Currently in ${currentGuilds.length} guilds, checking against ${data.length} in the database.`,
);

// Find any guilds that are in the database but not in the current guilds
const missingGuilds = data.filter(
(guild) => !currentGuilds.includes(guild.guildId),
);

// Find any guilds that are in the current guilds but not in the database
const newGuilds = currentGuilds.filter(
(id) => !data.some((guild) => guild.guildId === id),
);

// Update the database for missing guilds
try {
await Promise.all(
missingGuilds.map(async (guild) => {
console.log(`Removing guild from tracking: ${guild.guildId}`);
const result = await db
.update(dbDiscordTable)
.set({ isInServer: false })
.where(eq(dbDiscordTable.guildId, guild.guildId))
.returning();

if (result.length > 0) {
console.log(
`Successfully removed guild ${guild.guildId} from tracking.`,
);
} else {
console.error(
`Failed to remove guild ${guild.guildId} from tracking.`,
);
}
}),
);
} catch (error) {
console.error("Error while removing missing guilds:", error);
}

try {
await Promise.all(
newGuilds.map(async (guildId) => {
console.log(`Adding new guild to tracking: ${guildId}`);
const result = await db
.insert(dbDiscordTable)
.values({
guildId,
allowedPublicSharing: false,
feedrUpdatesChannelId: null,
isInServer: true,
memberCount: 0,
})
.returning();

if (result.length > 0) {
console.log(
`Successfully added guild ${guildId} to tracking.`,
);
} else {
console.error(
`Failed to add guild ${guildId} to tracking.`,
);
}
}),
);
} catch (error) {
console.error("Error while adding new guilds:", error);
}
}
3 changes: 1 addition & 2 deletions src/utils/youtube/fetchLatestUploads.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Platform } from "../../types/types.d.ts";

import { Platform } from "../../types/types.d";
import {
dbGuildYouTubeSubscriptionsTable,
dbYouTubeTable,
Expand Down