Skip to content

Commit 8b7b430

Browse files
committed
feat: move to sqlite
1 parent 50fc0b8 commit 8b7b430

File tree

16 files changed

+599
-470
lines changed

16 files changed

+599
-470
lines changed

.env.example

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@ DISCORD_DEV_TOKEN='YOUR_DISCORD_DEV_TOKEN'
99
# YouTube API Key
1010
YOUTUBE_API_KEY='YOUR_YOUTUBE_API_KEY'
1111

12-
# MySQL Database
13-
MYSQL_ADDRESS='YOUR_MYSQL_SERVER_ADDRESS'
14-
MYSQL_PORT='YOUR_MYSQL_SERVER_PORT'
15-
MYSQL_USER='YOUR_MYSQL_USER'
16-
MYSQL_PASSWORD='YOUR_MYSQL_PASSWORD'
17-
MYSQL_DATABASE='YOUR_DATABASE_NAME'
18-
1912
# Twitch
2013
TWITCH_CLIENT_ID='YOUR_TWITCH_CLIENT_ID'
2114
TWITCH_CLIENT_SECRET='YOUR_TWITCH_CLIENT_SECRET'

.eslintrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"sourceType": "module"
2121
},
2222
"rules": {
23-
"no-console": "warn",
23+
// "no-console": "warn",
2424
"prettier/prettier": [
2525
"warn",
2626
{

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
node_modules/
22
.env
33

4-
# backups of database
5-
*.sql
4+
*.db
5+
*.sqlite
6+
*.sqlite3

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@ Feedr requires Bun in order to work
5252

5353
## 1.3.0
5454

55-
- WIP
55+
- Moved database to SQLite
56+
- Added Bluesky
5657

5758
## 1.2.0
5859

bun.lockb

-3.54 KB
Binary file not shown.

package.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,29 @@
22
"name": "videonotifier",
33
"module": "src/index.ts",
44
"type": "module",
5-
"version": "1.3.0-wip",
5+
"version": "1.3.0",
66
"devDependencies": {
77
"@types/bun": "1.1.10",
8+
"@typescript-eslint/eslint-plugin": "8.11.0",
9+
"@typescript-eslint/parser": "8.11.0",
810
"eslint": "^8.57.0",
911
"eslint-config-prettier": "9.1.0",
1012
"eslint-plugin-import": "^2.26.0",
1113
"eslint-plugin-node": "^11.1.0",
1214
"eslint-plugin-prettier": "5.2.1",
13-
"eslint-plugin-unused-imports": "4.1.4",
14-
"@typescript-eslint/eslint-plugin": "8.11.0",
15-
"@typescript-eslint/parser": "8.11.0"
15+
"eslint-plugin-unused-imports": "4.1.4"
1616
},
1717
"peerDependencies": {
1818
"typescript": "^5.0.0"
1919
},
2020
"scripts": {
21+
"dev": "bun --watch . --dev",
22+
"test:jetstream": "bun --watch src/utils/bluesky/jetstream.ts",
2123
"lint": "eslint . --ext .ts -c .eslintrc.json",
2224
"lint:fix": "eslint . --ext .ts -c .eslintrc.json --fix"
2325
},
2426
"dependencies": {
25-
"discord.js": "^14.16.3",
26-
"mysql2": "^3.11.3"
27+
"cron": "^3.2.1",
28+
"discord.js": "^14.16.3"
2729
}
2830
}

src/config.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
// FILL IN THIS INFORMATION IN .ENV
22
export const config: { [key: string]: string | number } = {
3-
updateIntervalYouTube: process.env?.CONFIG_UPDATE_INTERVAL_YOUTUBE ? parseInt(process.env?.CONFIG_UPDATE_INTERVAL_YOUTUBE) * 1000 : 60_000,
4-
updateIntervalTwitch: process.env?.CONFIG_UPDATE_INTERVAL_TWITCH ? parseInt(process.env?.CONFIG_UPDATE_INTERVAL_TWITCH) * 1000 : 60_000,
5-
}
3+
updateIntervalYouTube: process.env?.CONFIG_UPDATE_INTERVAL_YOUTUBE
4+
? parseInt(process.env?.CONFIG_UPDATE_INTERVAL_YOUTUBE) * 1000
5+
: 60_000,
6+
updateIntervalTwitch: process.env?.CONFIG_UPDATE_INTERVAL_TWITCH
7+
? parseInt(process.env?.CONFIG_UPDATE_INTERVAL_TWITCH) * 1000
8+
: 60_000,
9+
};
610

711
export const env: { [key: string]: string | undefined } = {
8-
discordToken: process.argv.includes('--dev') ? process.env?.DISCORD_DEV_TOKEN : process.env?.DISCORD_TOKEN,
12+
discordToken: process.argv.includes("--dev")
13+
? process.env?.DISCORD_DEV_TOKEN
14+
: process.env?.DISCORD_TOKEN,
915
youtubeApiKey: process.env?.YOUTUBE_API_KEY,
10-
mysqlAddress: process.env?.MYSQL_ADDRESS,
11-
mysqlPort: process.env?.MYSQL_PORT,
12-
mysqlUser: process.env?.MYSQL_USER,
13-
mysqlPassword: process.env?.MYSQL_PASSWORD,
14-
mysqlDatabase: process.env?.MYSQL_DATABASE,
1516
twitchClientId: process.env?.TWITCH_CLIENT_ID,
1617
twitchClientSecret: process.env?.TWITCH_CLIENT_SECRET,
17-
};
18+
};

src/events/commandHandler.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import { Events } from "discord.js";
2-
import client from "..";
32

3+
import client from "..";
44
import commandsMap from "../commands";
55

66
client.on(Events.InteractionCreate, async (interaction) => {
7-
if (interaction.isChatInputCommand()) {
8-
const getCommand = commandsMap.get(interaction.commandName);
9-
if (!getCommand) {
10-
return console.log(`Command ${interaction.commandName} not found`);
11-
}
12-
return getCommand.execute(interaction);
13-
}
14-
});
7+
if (interaction.isChatInputCommand()) {
8+
const getCommand = commandsMap.get(interaction.commandName);
9+
10+
if (!getCommand) {
11+
return console.log(`Command ${interaction.commandName} not found`);
12+
}
13+
14+
return getCommand.execute(interaction);
15+
}
16+
});

src/index.ts

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,57 @@
11
// Check if all the required environment variables are set
2-
import { env } from './config.ts';
2+
import { env } from "./config.ts";
33

4-
if (!env.discordToken || env.discordToken === 'YOUR_DISCORD_TOKEN') {
5-
throw new Error('You MUST provide a discord token in .env!');
4+
if (!env.discordToken || env.discordToken === "YOUR_DISCORD_TOKEN") {
5+
throw new Error("You MUST provide a discord token in .env!");
66
}
77

8-
if (!env.youtubeApiKey || env.youtubeApiKey === 'YOUR_YOUTUBE_API_KEY') {
9-
throw new Error('You MUST provide a YouTube API key in .env!');
8+
if (!env.youtubeApiKey || env.youtubeApiKey === "YOUR_YOUTUBE_API_KEY") {
9+
throw new Error("You MUST provide a YouTube API key in .env!");
1010
}
1111

12-
if (!env.mysqlAddress || env.mysqlAddress === 'YOUR_MYSQL_SERVER_ADDRESS') {
13-
throw new Error('You MUST provide a MySQL server address in .env!');
12+
if (!env.twitchClientId || env.twitchClientId === "YOUR_TWITCH_CLIENT_ID") {
13+
throw new Error("You MUST provide a Twitch client ID in .env!");
1414
}
1515

16-
if (!env.mysqlPort || env.mysqlPort === 'YOUR_MYSQL_SERVER_PORT') {
17-
throw new Error('You MUST provide a MySQL server port in .env!');
16+
if (
17+
!env.twitchClientSecret ||
18+
env.twitchClientSecret === "YOUR_TWITCH_CLIENT_SECRET"
19+
) {
20+
throw new Error("You MUST provide a Twitch client secret in .env!");
1821
}
1922

20-
if (!env.mysqlUser || env.mysqlUser === 'YOUR_MYSQL_USER') {
21-
throw new Error('You MUST provide a MySQL user in .env!');
22-
}
23+
// If everything is set up correctly, continue with the bot
24+
import {
25+
Client,
26+
GatewayIntentBits,
27+
REST,
28+
Routes,
29+
type APIApplicationCommand,
30+
} from "discord.js";
2331

24-
if (!env.mysqlPassword || env.mysqlPassword === 'YOUR_MYSQL_PASSWORD') {
25-
throw new Error('You MUST provide a MySQL password in .env!');
26-
}
32+
import commandsMap from "./commands.ts";
2733

28-
if (!env.mysqlDatabase || env.mysqlDatabase === 'YOUR_DATABASE_NAME') {
29-
throw new Error('You MUST provide a database name in .env!');
30-
}
34+
import fs from "fs/promises";
35+
import path from "path";
3136

32-
if (!env.twitchClientId || env.twitchClientId === 'YOUR_TWITCH_CLIENT_ID') {
33-
throw new Error('You MUST provide a Twitch client ID in .env!');
34-
}
37+
import { initTables } from "./utils/database.ts";
38+
import { getTwitchToken } from "./utils/twitch/auth.ts";
3539

36-
if (!env.twitchClientSecret || env.twitchClientSecret === 'YOUR_TWITCH_CLIENT_SECRET') {
37-
throw new Error('You MUST provide a Twitch client secret in .env!');
38-
}
40+
import { CronJob } from "cron";
3941

40-
// Import API
41-
import './api.ts'
42+
import backup from "./utils/backup.ts";
4243

43-
// If everything is set up correctly, continue with the bot
44-
import { Client, GatewayIntentBits, REST, Routes, type APIApplicationCommand } from 'discord.js';
45-
import commandsMap from './commands.ts';
46-
import fs from 'fs/promises';
47-
import path from 'path';
48-
import { initTables } from './utils/database.ts';
49-
import { getTwitchToken } from './utils/twitch/auth.ts';
44+
// Start the cron jobs
45+
await fs.mkdir(path.resolve(process.cwd(), "backups"), { recursive: true });
46+
new CronJob("0 0 * * *", async () => {
47+
await backup(
48+
path.resolve(process.cwd(), "db.sqlite3"),
49+
`./backups/db-${new Date().toISOString().replace(/[:.]/g, "-")}.sqlite3`,
50+
);
51+
}).start();
5052

5153
const client = new Client({
52-
intents: [
53-
GatewayIntentBits.Guilds,
54-
GatewayIntentBits.GuildMessages,
55-
]
54+
intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages],
5655
});
5756

5857
// Update the commands
@@ -61,6 +60,7 @@ const rest = new REST().setToken(env.discordToken);
6160
const getAppId: { id?: string | null } = (await rest.get(
6261
Routes.currentApplication(),
6362
)) || { id: null };
63+
6464
if (!getAppId?.id)
6565
throw "No application ID was able to be found with this token";
6666

@@ -73,22 +73,25 @@ const data = (await rest.put(Routes.applicationCommands(getAppId.id), {
7373
console.log(`Successfully reloaded ${data.length} application (/) commands.`);
7474

7575
// Check if MySQL is set up properly and its working
76-
if (!await initTables()) {
77-
throw new Error('Error initializing tables');
76+
if (!(await initTables())) {
77+
throw new Error("Error initializing tables");
7878
}
7979

8080
// Get Twitch token
81-
if (!await getTwitchToken()) {
82-
throw new Error('Error getting Twitch token');
81+
if (!(await getTwitchToken())) {
82+
throw new Error("Error getting Twitch token");
8383
}
8484

8585
// Login to Discord
8686
client.login(env.discordToken);
8787

88-
export default client
88+
export default client;
8989

9090
// Import events
91-
const getEvents = await fs.readdir(path.resolve(__dirname, './events'));
92-
await Promise.all(getEvents.map(async (file) => {
93-
await import('./events/' + file);
94-
}));
91+
const getEvents = await fs.readdir(path.resolve(__dirname, "./events"));
92+
93+
await Promise.all(
94+
getEvents.map(async (file) => {
95+
await import("./events/" + file);
96+
}),
97+
);

src/types/database.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
export interface dbYouTube {
2-
channelId: string;
3-
lastVideoId: string;
2+
channelId: string;
3+
lastVideoId: string;
44
}
55

66
export interface dbTwitch {
7-
twitch_channel_id: string;
8-
is_live: boolean;
9-
}
7+
twitch_channel_id: string;
8+
is_live: boolean;
9+
}

0 commit comments

Comments
 (0)