mirror of
https://github.com/ZHANGTIANYAO1/teamspeak-music-bot.git
synced 2026-10-02 04:52:50 +08:00
feat(spotify): web OAuth endpoints + thread single shared SpotifyOAuth to web + controllers (Stage 3, Task 6)
Add the /api/spotify {login,callback,status} router behind the SpotifyOAuthLike
seam (DI-tested with supertest, no network). Build ONE process-wide SpotifyOAuth
in index.ts (clientId/redirectUri from config; store via the already-exported
createFileOAuthTokenStore) and thread that same instance into BOTH createWebServer
AND BotManager -> BotInstance -> SpotifyController, so a web login authorizes
playback (C3.1). Reuses the existing file token store (no token-store.ts).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
322335dfc5
commit
8998b9623f
8 files changed
+363
-2
No files matched your search
@@ -27,6 +27,7 @@ import { isSpotifyUri } from "../music/spotify/webapi.js";
|
||||
import path from "node:path";
|
||||
import { SpotifyController } from "../music/spotify/controller.js";
|
||||
import type { SpotifyTrackEndedEvent } from "../music/spotify/backend.js";
|
||||
import type { SpotifyOAuth } from "../music/spotify/spotify-oauth.js";
|
||||
|
||||
/** Reply sent when a non-admin invokes an admin-only chat command. */
|
||||
export const COMMAND_DENIED_MESSAGE = "⛔ 需要管理员权限(该命令仅限管理员服务器组)";
|
||||
@@ -77,6 +78,9 @@ export interface BotInstanceOptions {
|
||||
avatarStore: AvatarStore;
|
||||
/** Base dir (under DATA_DIR) for per-bot go-librespot work/config trees. */
|
||||
spotifyDataDir?: string;
|
||||
/** Process-wide shared Spotify OAuth (single account); injected into the
|
||||
* SpotifyController so web-login authorization is visible to playback (C3.1). */
|
||||
spotifyOAuth?: SpotifyOAuth;
|
||||
/** Test seam: build a fake controller instead of a real go-librespot one. */
|
||||
spotifyControllerFactory?: (o: {
|
||||
config: SpotifyConfig;
|
||||
@@ -85,6 +89,7 @@ export interface BotInstanceOptions {
|
||||
logger: Logger;
|
||||
apiPort: number;
|
||||
callbackPort: number;
|
||||
oauth?: SpotifyOAuth;
|
||||
}) => SpotifyController;
|
||||
}
|
||||
|
||||
@@ -181,6 +186,7 @@ export class BotInstance extends EventEmitter {
|
||||
logger: this.logger,
|
||||
apiPort: spotifyApiPort,
|
||||
callbackPort: spotifyCallbackPort,
|
||||
oauth: options.spotifyOAuth,
|
||||
});
|
||||
|
||||
const profileConfig = this.database.getProfileConfig(this.id);
|
||||
@@ -1412,6 +1418,13 @@ export class BotInstance extends EventEmitter {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
/** The per-bot Spotify sidecar controller. Exposed like getPlayer()/
|
||||
* getQueueManager() so the shared, process-wide OAuth threaded in at
|
||||
* construction (C3.1) is observable to callers/tests via getOAuth(). */
|
||||
getSpotifyController(): SpotifyController {
|
||||
return this.spotifyController;
|
||||
}
|
||||
|
||||
/**
|
||||
* Route a seek to the Spotify sidecar for a spotify track (its PCM stream is
|
||||
* external — AudioPlayer.seek would respawn ffmpeg on the `spotify:` sentinel
|
||||
|
||||
Reference in new issue
Block a user