feat(bot): load custom avatar on instance startup

Thread AvatarStore from index.ts → BotManager → BotInstance so every
BotInstance reads the persisted custom avatar from disk at construction
time and hands it to BotProfileManager via setCustomAvatar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
saopig1andClaude Sonnet 4.6 committed 2026-05-07 20:07:47 +08:00
1 parent ffa27d7224
commit 2dd6a9e20d
3 files changed
+23 -2

No files matched your search

+10
View File
@@ -16,6 +16,7 @@ import type { Logger } from "../logger.js";
import type { BotDatabase, ProfileConfig } from "../data/database.js";
import type { BotConfig } from "../data/config.js";
import { BotProfileManager } from "./profile.js";
import type { AvatarStore } from "../data/avatars.js";
export interface BotInstanceOptions {
id: string;
@@ -28,6 +29,7 @@ export interface BotInstanceOptions {
database: BotDatabase;
config: BotConfig;
logger: Logger;
avatarStore: AvatarStore;
}
export interface BotStatus {
@@ -57,6 +59,7 @@ export class BotInstance extends EventEmitter {
private database: BotDatabase;
private config: BotConfig;
private logger: Logger;
private avatarStore: AvatarStore;
private connected = false;
private disconnectEmitted = false;
private voteSkipUsers = new Set<string>();
@@ -77,6 +80,7 @@ export class BotInstance extends EventEmitter {
this.database = options.database;
this.config = options.config;
this.logger = options.logger.child({ botId: this.id });
this.avatarStore = options.avatarStore;
this.tsClient = new TS3Client(options.tsOptions, this.logger);
this.player = new AudioPlayer(this.logger);
@@ -90,6 +94,12 @@ export class BotInstance extends EventEmitter {
options.tsOptions.nickname,
);
const relPath = this.database.getCustomAvatarPath(this.id);
if (relPath) {
const buf = this.avatarStore.read(relPath);
if (buf) this.profileManager.setCustomAvatar(buf);
}
this.setupPlayerEvents();
this.setupTsEvents();
}
+8 -1
View File
@@ -11,6 +11,7 @@ import type { BotConfig } from "../data/config.js";
import type { Logger } from "../logger.js";
import type { ServerProtocol } from "../ts-protocol/client.js";
import type { AvatarStore } from "../data/avatars.js";
/**
* Run bot.connect() with a hard deadline. If the handshake hangs (e.g. the
@@ -74,6 +75,7 @@ export class BotManager extends EventEmitter {
private database: BotDatabase;
private config: BotConfig;
private logger: Logger;
private avatarStore: AvatarStore;
constructor(
neteaseProvider: MusicProvider,
@@ -81,7 +83,8 @@ export class BotManager extends EventEmitter {
bilibiliProvider: MusicProvider,
database: BotDatabase,
config: BotConfig,
logger: Logger
logger: Logger,
avatarStore: AvatarStore
) {
super();
this.neteaseProvider = neteaseProvider;
@@ -91,6 +94,7 @@ export class BotManager extends EventEmitter {
this.database = database;
this.config = config;
this.logger = logger;
this.avatarStore = avatarStore;
}
async createBot(params: CreateBotParams): Promise<BotInstance> {
@@ -117,6 +121,7 @@ export class BotManager extends EventEmitter {
database: this.database,
config: this.config,
logger: this.logger,
avatarStore: this.avatarStore,
});
this.bots.set(id, bot);
@@ -233,6 +238,7 @@ export class BotManager extends EventEmitter {
database: this.database,
config: this.config,
logger: this.logger,
avatarStore: this.avatarStore,
});
this.bots.set(id, bot);
this.emit("botInstance", bot);
@@ -283,6 +289,7 @@ export class BotManager extends EventEmitter {
database: this.database,
config: this.config,
logger: this.logger,
avatarStore: this.avatarStore,
});
this.bots.set(saved.id, bot);
+5 -1
View File
@@ -8,6 +8,7 @@ import { NeteaseProvider } from "./music/netease.js";
import { QQMusicProvider } from "./music/qq.js";
import { BiliBiliProvider } from "./music/bilibili.js";
import { createCookieStore } from "./music/auth.js";
import { createAvatarStore } from "./data/avatars.js";
import { BotManager } from "./bot/manager.js";
import { createWebServer } from "./web/server.js";
@@ -18,6 +19,7 @@ const CONFIG_PATH = path.join(ROOT_DIR, "config.json");
const DB_PATH = path.join(DATA_DIR, "tsmusicbot.db");
const LOG_DIR = path.join(DATA_DIR, "logs");
const COOKIE_DIR = path.join(DATA_DIR, "cookies");
const AVATAR_DIR = path.join(DATA_DIR, "avatars");
const STATIC_DIR = path.join(ROOT_DIR, "web", "dist");
async function main() {
@@ -46,6 +48,7 @@ async function main() {
const bilibiliProvider = new BiliBiliProvider();
const cookieStore = createCookieStore(COOKIE_DIR);
const avatarStore = createAvatarStore(AVATAR_DIR);
const neteaseCookie = cookieStore.load("netease");
if (neteaseCookie) neteaseProvider.setCookie(neteaseCookie);
const qqCookie = cookieStore.load("qq");
@@ -59,7 +62,8 @@ async function main() {
bilibiliProvider,
db,
config,
logger
logger,
avatarStore
);
await botManager.loadSavedBots();