mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat: persist volume, play mode and audio quality across restarts
Runtime playback settings were kept only in memory (AudioPlayer.volume, PlayQueue.mode, each provider's quality field), so restarting the bot reset them to defaults and users had to re-tune volume and quality every time (#125). Persist and restore them via the repo's existing storage: - Volume and play mode are per-bot, stored on new bot_instances columns (volume, play_mode) with a schema migration; restored when the instance is (re)built, written by cmdVol / cmdMode which every entry point (chat command, WebUI, REST) funnels through. Volume and mode are written independently so a transient !fm/!artist mode switch never overwrites the user's saved !mode. - Per-provider audio quality is global (shared providers), stored in a new config.json `audioQuality` block; applied to the providers at startup and re-snapshotted on POST /api/music/quality. Queue, current song, progress and FM/artist sessions stay ephemeral. Adds tests for config sanitize/round-trip, DB player-settings + migration, cmdVol/cmdMode persistence + construction-time restore, and quality persistence through the REST endpoint. Documents the behavior in the README. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
051171b019
commit
fbd94c424b
11 files changed
+618
-12
No files matched your search
@@ -38,6 +38,22 @@ export interface JellyfinConfig {
|
||||
userId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-provider audio quality (音质), persisted so a restart keeps the user's
|
||||
* choice instead of resetting each provider to its in-memory default (#125).
|
||||
* The values are the same strings the WebUI/REST `POST /api/music/quality`
|
||||
* endpoint sends and each provider's setQuality() accepts; on startup they are
|
||||
* replayed onto the (shared, process-wide) providers. Providers ignore/normalize
|
||||
* unknown values, so a stale/hand-edited entry can never break playback.
|
||||
*/
|
||||
export interface AudioQualityConfig {
|
||||
netease: string;
|
||||
qq: string;
|
||||
bilibili: string;
|
||||
kugou: string;
|
||||
jellyfin: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Providers gated by `enabledProviders`. Not listed here:
|
||||
* - "local" → governed by the existing `localAudioEnabled` flag
|
||||
@@ -102,6 +118,8 @@ export interface BotConfig {
|
||||
guestMode: GuestModeConfig;
|
||||
spotify: SpotifyConfig;
|
||||
jellyfin: JellyfinConfig;
|
||||
/** Persisted per-provider audio quality (音质), restored on startup (#125). */
|
||||
audioQuality: AudioQualityConfig;
|
||||
/**
|
||||
* Which gateable providers are active (see GATEABLE_PROVIDERS). Default is
|
||||
* the online sources (NetEase/QQ/Bilibili/YouTube/Kugou); jellyfin is an
|
||||
@@ -162,6 +180,15 @@ export function getDefaultConfig(): BotConfig {
|
||||
apiKey: "",
|
||||
userId: "",
|
||||
},
|
||||
// Mirrors each provider's own in-memory default quality; overwritten on
|
||||
// startup once the user has changed a quality (persisted via #125).
|
||||
audioQuality: {
|
||||
netease: "exhigh",
|
||||
qq: "exhigh",
|
||||
bilibili: "high",
|
||||
kugou: "128",
|
||||
jellyfin: "direct",
|
||||
},
|
||||
enabledProviders: ["netease", "qq", "bilibili", "youtube", "kugou"],
|
||||
};
|
||||
}
|
||||
@@ -317,6 +344,20 @@ export function loadConfig(path: string): BotConfig {
|
||||
)
|
||||
: defaults.enabledProviders;
|
||||
|
||||
// audioQuality → per-provider strings; each field falls back to its default
|
||||
// when missing/blank/non-string (a hand-edited/legacy config must never smuggle
|
||||
// a non-string past the gate — the value is fed straight to provider.setQuality).
|
||||
const partialAq = (partial.audioQuality ?? {}) as Partial<AudioQualityConfig>;
|
||||
const coerceQuality = (v: unknown, fallback: string): string =>
|
||||
typeof v === "string" && v.trim() ? v : fallback;
|
||||
const audioQuality: AudioQualityConfig = {
|
||||
netease: coerceQuality(partialAq.netease, defaults.audioQuality.netease),
|
||||
qq: coerceQuality(partialAq.qq, defaults.audioQuality.qq),
|
||||
bilibili: coerceQuality(partialAq.bilibili, defaults.audioQuality.bilibili),
|
||||
kugou: coerceQuality(partialAq.kugou, defaults.audioQuality.kugou),
|
||||
jellyfin: coerceQuality(partialAq.jellyfin, defaults.audioQuality.jellyfin),
|
||||
};
|
||||
|
||||
return {
|
||||
...defaults,
|
||||
...partial,
|
||||
@@ -324,6 +365,7 @@ export function loadConfig(path: string): BotConfig {
|
||||
guestMode: gm,
|
||||
spotify,
|
||||
jellyfin,
|
||||
audioQuality,
|
||||
enabledProviders,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user