feat: add SQLite database module with play history and bot instances

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Opus 4.6 committed 2026-03-30 00:21:07 +08:00
1 parent 6324953394
commit 8727605036
2 files changed
+225

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
import Database from "better-sqlite3";
export interface PlayHistoryRecord {
id?: number;
botId: string;
songId: string;
songName: string;
artist: string;
album: string;
platform: string;
coverUrl: string;
playedAt: string;
}
export interface BotInstance {
id: string;
name: string;
serverAddress: string;
serverPort: number;
nickname: string;
defaultChannel: string;
channelPassword: string;
autoStart: boolean;
}
export interface BotDatabase {
db: Database.Database;
addPlayHistory(record: Omit<PlayHistoryRecord, "id">): void;
getPlayHistory(botId: string, limit: number): PlayHistoryRecord[];
saveBotInstance(instance: BotInstance): void;
getBotInstances(): BotInstance[];
deleteBotInstance(id: string): boolean;
close(): void;
}
function initTables(db: Database.Database): void {
db.exec(`
CREATE TABLE IF NOT EXISTS play_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
botId TEXT NOT NULL,
songId TEXT NOT NULL,
songName TEXT NOT NULL,
artist TEXT NOT NULL,
album TEXT NOT NULL,
platform TEXT NOT NULL,
coverUrl TEXT NOT NULL,
playedAt TEXT NOT NULL
);
CREATE TABLE IF NOT EXISTS bot_instances (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
serverAddress TEXT NOT NULL,
serverPort INTEGER NOT NULL,
nickname TEXT NOT NULL,
defaultChannel TEXT NOT NULL,
channelPassword TEXT NOT NULL,
autoStart INTEGER NOT NULL DEFAULT 0
);
`);
}
export function createDatabase(dbPath: string): BotDatabase {
const db = new Database(dbPath);
db.pragma("journal_mode = WAL");
initTables(db);
const insertHistory = db.prepare(`
INSERT INTO play_history (botId, songId, songName, artist, album, platform, coverUrl, playedAt)
VALUES (@botId, @songId, @songName, @artist, @album, @platform, @coverUrl, @playedAt)
`);
const selectHistory = db.prepare(`
SELECT * FROM play_history WHERE botId = ? ORDER BY id DESC LIMIT ?
`);
const upsertInstance = db.prepare(`
INSERT INTO bot_instances (id, name, serverAddress, serverPort, nickname, defaultChannel, channelPassword, autoStart)
VALUES (@id, @name, @serverAddress, @serverPort, @nickname, @defaultChannel, @channelPassword, @autoStart)
ON CONFLICT(id) DO UPDATE SET
name = excluded.name,
serverAddress = excluded.serverAddress,
serverPort = excluded.serverPort,
nickname = excluded.nickname,
defaultChannel = excluded.defaultChannel,
channelPassword = excluded.channelPassword,
autoStart = excluded.autoStart
`);
const selectInstances = db.prepare(`SELECT * FROM bot_instances`);
const deleteInstance = db.prepare(`DELETE FROM bot_instances WHERE id = ?`);
return {
db,
addPlayHistory(record) {
insertHistory.run(record);
},
getPlayHistory(botId, limit) {
return selectHistory.all(botId, limit) as PlayHistoryRecord[];
},
saveBotInstance(instance) {
upsertInstance.run({
...instance,
autoStart: instance.autoStart ? 1 : 0,
});
},
getBotInstances() {
const rows = selectInstances.all() as Array<
Omit<BotInstance, "autoStart"> & { autoStart: number }
>;
return rows.map((r) => ({ ...r, autoStart: r.autoStart === 1 }));
},
deleteBotInstance(id) {
const result = deleteInstance.run(id);
return result.changes > 0;
},
close() {
db.close();
},
};
}