mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat(spotify): config block (disabled by default) + sanitize
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
828fd21e29
commit
848b3931b8
2 files changed
+97
No files matched your search
@@ -205,3 +205,61 @@ describe("adminGroups normalization", () => {
|
|||||||
expect(loadAdminGroups({ adminGroups: "6" })).toEqual([]);
|
expect(loadAdminGroups({ adminGroups: "6" })).toEqual([]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("spotify config", () => {
|
||||||
|
it("defaults are present and disabled", () => {
|
||||||
|
const c = getDefaultConfig();
|
||||||
|
expect(c.spotify).toEqual({
|
||||||
|
enabled: false,
|
||||||
|
backend: "auto",
|
||||||
|
clientId: "",
|
||||||
|
clientSecret: "",
|
||||||
|
deviceName: "TSMusicBot",
|
||||||
|
bitrate: 320,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("loadConfig coerces bad spotify values back to safe defaults", () => {
|
||||||
|
const dir = mkdtempSync(join(tmpdir(), "cfg-"));
|
||||||
|
const p = join(dir, "config.json");
|
||||||
|
writeFileSync(
|
||||||
|
p,
|
||||||
|
JSON.stringify({
|
||||||
|
spotify: { enabled: "yes", backend: "bogus", bitrate: 7, clientId: 5 },
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const c = loadConfig(p);
|
||||||
|
expect(c.spotify.enabled).toBe(false); // non-boolean → false
|
||||||
|
expect(c.spotify.backend).toBe("auto"); // invalid enum → auto
|
||||||
|
expect(c.spotify.bitrate).toBe(320); // invalid → 320
|
||||||
|
expect(c.spotify.clientId).toBe(""); // non-string → ""
|
||||||
|
expect(c.spotify.deviceName).toBe("TSMusicBot"); // missing → default
|
||||||
|
});
|
||||||
|
|
||||||
|
it("loadConfig preserves valid spotify values", () => {
|
||||||
|
const dir = mkdtempSync(join(tmpdir(), "cfg-"));
|
||||||
|
const p = join(dir, "config.json");
|
||||||
|
writeFileSync(
|
||||||
|
p,
|
||||||
|
JSON.stringify({
|
||||||
|
spotify: {
|
||||||
|
enabled: true,
|
||||||
|
backend: "librespot",
|
||||||
|
clientId: "abc",
|
||||||
|
clientSecret: "def",
|
||||||
|
deviceName: "MyBot",
|
||||||
|
bitrate: 160,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const c = loadConfig(p);
|
||||||
|
expect(c.spotify).toEqual({
|
||||||
|
enabled: true,
|
||||||
|
backend: "librespot",
|
||||||
|
clientId: "abc",
|
||||||
|
clientSecret: "def",
|
||||||
|
deviceName: "MyBot",
|
||||||
|
bitrate: 160,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -9,6 +9,15 @@ export interface GuestModeConfig {
|
|||||||
permissions: GuestPermissions;
|
permissions: GuestPermissions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SpotifyConfig {
|
||||||
|
enabled: boolean;
|
||||||
|
backend: "auto" | "go-librespot" | "librespot";
|
||||||
|
clientId: string;
|
||||||
|
clientSecret: string;
|
||||||
|
deviceName: string;
|
||||||
|
bitrate: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface BotConfig {
|
export interface BotConfig {
|
||||||
webPort: number;
|
webPort: number;
|
||||||
locale: "zh" | "en";
|
locale: "zh" | "en";
|
||||||
@@ -33,6 +42,7 @@ export interface BotConfig {
|
|||||||
// behind HTTPS-terminating proxies.
|
// behind HTTPS-terminating proxies.
|
||||||
trustProxy: boolean;
|
trustProxy: boolean;
|
||||||
guestMode: GuestModeConfig;
|
guestMode: GuestModeConfig;
|
||||||
|
spotify: SpotifyConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDefaultConfig(): BotConfig {
|
export function getDefaultConfig(): BotConfig {
|
||||||
@@ -69,6 +79,14 @@ export function getDefaultConfig(): BotConfig {
|
|||||||
playCollection: false,
|
playCollection: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
spotify: {
|
||||||
|
enabled: false,
|
||||||
|
backend: "auto",
|
||||||
|
clientId: "",
|
||||||
|
clientSecret: "",
|
||||||
|
deviceName: "TSMusicBot",
|
||||||
|
bitrate: 320,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,11 +136,32 @@ export function loadConfig(path: string): BotConfig {
|
|||||||
)
|
)
|
||||||
: defaults.adminGroups;
|
: defaults.adminGroups;
|
||||||
|
|
||||||
|
const partialSp = (partial.spotify ?? {}) as Partial<SpotifyConfig>;
|
||||||
|
const validBackends = ["auto", "go-librespot", "librespot"] as const;
|
||||||
|
const validBitrates = [96, 160, 320];
|
||||||
|
const spotify: SpotifyConfig = {
|
||||||
|
enabled: partialSp.enabled === true,
|
||||||
|
backend: (validBackends as readonly string[]).includes(partialSp.backend as string)
|
||||||
|
? (partialSp.backend as SpotifyConfig["backend"])
|
||||||
|
: defaults.spotify.backend,
|
||||||
|
clientId: typeof partialSp.clientId === "string" ? partialSp.clientId : defaults.spotify.clientId,
|
||||||
|
clientSecret:
|
||||||
|
typeof partialSp.clientSecret === "string" ? partialSp.clientSecret : defaults.spotify.clientSecret,
|
||||||
|
deviceName:
|
||||||
|
typeof partialSp.deviceName === "string" && partialSp.deviceName.trim()
|
||||||
|
? partialSp.deviceName
|
||||||
|
: defaults.spotify.deviceName,
|
||||||
|
bitrate: validBitrates.includes(partialSp.bitrate as number)
|
||||||
|
? (partialSp.bitrate as number)
|
||||||
|
: defaults.spotify.bitrate,
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...defaults,
|
...defaults,
|
||||||
...partial,
|
...partial,
|
||||||
adminGroups,
|
adminGroups,
|
||||||
guestMode: gm,
|
guestMode: gm,
|
||||||
|
spotify,
|
||||||
};
|
};
|
||||||
} catch {
|
} catch {
|
||||||
return defaults;
|
return defaults;
|
||||||
|
|||||||
Reference in new issue
Block a user