feat(selfbot): dedicated DISCORD_STREAM_TOKEN for the broadcast account
Confirmed root cause of "broadcast doesn't appear in Discord" in userbot mode:
the conversation and the Go-Live broadcaster were the SAME Discord account on
two sessions. Discord allows one voice presence per account, so the broadcaster's
voice connection never connects (state voiceReady:false). Proven by isolating the
broadcaster: alone it connects ("Go-Live WebRTC connected"); alongside the
conversation it times out.
The broadcaster now logs in with DISCORD_STREAM_TOKEN when set (a second burner
account dedicated to streaming), falling back to DISCORD_SELFBOT_TOKEN (correct
for normal-bot mode). When userbot mode shares one account it warns loudly with
the fix. Documents the var in .env.example.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -123,6 +123,14 @@ VNC_BITRATE_KBPS=8000
|
|||||||
# A THROWAWAY/burner Discord user account token. NEVER your main account.
|
# A THROWAWAY/burner Discord user account token. NEVER your main account.
|
||||||
# Using a selfbot violates Discord ToS and can get the account banned.
|
# Using a selfbot violates Discord ToS and can get the account banned.
|
||||||
DISCORD_SELFBOT_TOKEN=
|
DISCORD_SELFBOT_TOKEN=
|
||||||
|
# Dedicated burner account for the Go-Live BROADCAST, separate from the
|
||||||
|
# conversation account above. REQUIRED in userbot mode for the broadcast to
|
||||||
|
# work: Discord allows only one voice presence per account, so the conversation
|
||||||
|
# and the broadcast cannot share one account (the broadcaster's voice connection
|
||||||
|
# never connects). Leave empty in normal-bot mode (the conversation runs on the
|
||||||
|
# bot account, so the selfbot account is already broadcast-only). Both burner
|
||||||
|
# accounts must be in the server. Use a second throwaway account, never a main.
|
||||||
|
DISCORD_STREAM_TOKEN=
|
||||||
# Hardware (NVENC) encode for the stream. 1 = use the GPU (recommended for
|
# Hardware (NVENC) encode for the stream. 1 = use the GPU (recommended for
|
||||||
# 1080p60), 0 = software x264. Requires an NVIDIA GPU + ffmpeg built with nvenc.
|
# 1080p60), 0 = software x264. Requires an NVIDIA GPU + ffmpeg built with nvenc.
|
||||||
STREAM_HW=1
|
STREAM_HW=1
|
||||||
|
|||||||
@@ -46,6 +46,14 @@ export const config = {
|
|||||||
|
|
||||||
// selfbot backend (ToS-risk; use a throwaway account token, never your main)
|
// selfbot backend (ToS-risk; use a throwaway account token, never your main)
|
||||||
selfbotToken: opt("DISCORD_SELFBOT_TOKEN"),
|
selfbotToken: opt("DISCORD_SELFBOT_TOKEN"),
|
||||||
|
// Account used for the Go-Live broadcast. In userbot mode the conversation and
|
||||||
|
// the broadcast CANNOT share one account: Discord allows a single voice
|
||||||
|
// presence per account, so the broadcaster's second session never connects
|
||||||
|
// (confirmed: alone it goes Live, alongside the conversation it times out).
|
||||||
|
// Set DISCORD_STREAM_TOKEN to a SECOND burner account dedicated to the
|
||||||
|
// broadcast. Empty = reuse DISCORD_SELFBOT_TOKEN (correct for normal-bot mode,
|
||||||
|
// where the conversation runs on the bot account, not the selfbot account).
|
||||||
|
streamToken: opt("DISCORD_STREAM_TOKEN"),
|
||||||
// How long to wait for the Go-Live stream WebRTC to actually reach
|
// How long to wait for the Go-Live stream WebRTC to actually reach
|
||||||
// "connected" before declaring the broadcast failed (and tearing the local
|
// "connected" before declaring the broadcast failed (and tearing the local
|
||||||
// ffmpeg pipeline down). Guards against reporting "live" when nothing reaches
|
// ffmpeg pipeline down). Guards against reporting "live" when nothing reaches
|
||||||
|
|||||||
@@ -130,8 +130,23 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
if (this.config.screenBrowser === false) {
|
if (this.config.screenBrowser === false) {
|
||||||
return "화면 공유(브라우저) 모드가 꺼져 있습니다 (STREAM_BROWSER=false). 음성 + API/MCP 모드로만 동작합니다.";
|
return "화면 공유(브라우저) 모드가 꺼져 있습니다 (STREAM_BROWSER=false). 음성 + API/MCP 모드로만 동작합니다.";
|
||||||
}
|
}
|
||||||
if (!this.config.selfbotToken) {
|
// Broadcast account: a dedicated DISCORD_STREAM_TOKEN if provided, otherwise
|
||||||
return "DISCORD_SELFBOT_TOKEN이 설정되지 않았습니다 (.env). 버너 계정 토큰을 넣어주세요.";
|
// reuse the conversation's selfbot token. In userbot mode (no normal-bot
|
||||||
|
// token) sharing one account fails — the broadcaster's voice connection
|
||||||
|
// can't establish alongside the conversation's, so the Go-Live never
|
||||||
|
// connects. Warn loudly in that case so the failure is self-explanatory.
|
||||||
|
const streamToken = this.config.streamToken || this.config.selfbotToken;
|
||||||
|
if (!streamToken) {
|
||||||
|
return "DISCORD_SELFBOT_TOKEN(또는 DISCORD_STREAM_TOKEN)이 설정되지 않았습니다 (.env). 버너 계정 토큰을 넣어주세요.";
|
||||||
|
}
|
||||||
|
const dedicatedStreamAccount =
|
||||||
|
!!this.config.streamToken && this.config.streamToken !== this.config.selfbotToken;
|
||||||
|
if (!dedicatedStreamAccount && !this.config.botToken) {
|
||||||
|
console.warn(
|
||||||
|
"[selfbot] ⚠️ 방송과 대화가 같은 계정(DISCORD_SELFBOT_TOKEN)을 사용합니다. " +
|
||||||
|
"유저봇 모드에서는 음성 채널을 동시에 점유할 수 없어 Go-Live가 연결되지 않습니다. " +
|
||||||
|
"방송 전용 DISCORD_STREAM_TOKEN(별도 버너 계정)을 설정하세요.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (!ctx.voiceChannelId) {
|
if (!ctx.voiceChannelId) {
|
||||||
return "셀프봇 송출은 음성 채널 안에서 호출해야 합니다.";
|
return "셀프봇 송출은 음성 채널 안에서 호출해야 합니다.";
|
||||||
@@ -158,7 +173,7 @@ export class SelfbotStreamer implements ScreenStreamer {
|
|||||||
signal.throwIfAborted();
|
signal.throwIfAborted();
|
||||||
|
|
||||||
streamer = this.streamer = new Streamer(new selfbot.Client());
|
streamer = this.streamer = new Streamer(new selfbot.Client());
|
||||||
await streamer.client.login(this.config.selfbotToken);
|
await streamer.client.login(streamToken);
|
||||||
signal.throwIfAborted();
|
signal.throwIfAborted();
|
||||||
|
|
||||||
// Act like a person, not a bot: take a breath after coming online before
|
// Act like a person, not a bot: take a breath after coming online before
|
||||||
|
|||||||
Reference in New Issue
Block a user