feat(stream): single-account Go-Live — broadcast on the conversation's session
Proven approach: the conversation (hear+speak) runs on @discordjs/voice; the
Go-Live broadcast is a SEPARATE stream connection created on the SAME selfbot
session (exactly like a real Discord client), so ONE account hears, speaks, AND
broadcasts — no second login, no self_deaf, no voice conflict.
- voice.ts captures its own voice session_id (adapter wrap) and exposes
getSharedSession() {client, guildId, channelId, sessionId, botId}.
- broadcast.ts threads it into the StreamContext.
- selfbot.ts: when a shared session is present, build the Streamer on the
conversation client and create the stream on its session_id (no login/joinVoice/
humanPause); teardown only stops the stream (never leaves voice/destroys the
shared client). Falls back to the dedicated-account path otherwise.
Verified live: Go-Live connected in ~7s while the conversation voice stayed
ready, and the broadcast was visible in Discord — all on one account.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,10 @@ export function peekStreamer(guildId: string): ScreenStreamer | undefined {
|
||||
return streamers.get(guildId);
|
||||
}
|
||||
|
||||
type BroadcastSession = Pick<VoiceSession, "getBroadcasting" | "onBroadcastAction">;
|
||||
type BroadcastSession = Pick<
|
||||
VoiceSession,
|
||||
"getBroadcasting" | "onBroadcastAction" | "getSharedSession"
|
||||
>;
|
||||
|
||||
/**
|
||||
* Wire a voice session to a streamer (no auto-start). Pure (no config / registry
|
||||
@@ -107,8 +110,14 @@ export async function maybeCoupleBroadcast(
|
||||
): Promise<void> {
|
||||
if (!config.screenBrowser) return;
|
||||
const streamer = await getStreamer(ctx.guildId);
|
||||
wireBroadcast(session, streamer, ctx);
|
||||
void autoStartBroadcast(streamer, ctx);
|
||||
// Let the selfbot backend broadcast on the conversation's own session
|
||||
// (single-account Go-Live) instead of a second login.
|
||||
const ctxWithSession: StreamContext = {
|
||||
...ctx,
|
||||
getSharedSession: () => session.getSharedSession?.() ?? null,
|
||||
};
|
||||
wireBroadcast(session, streamer, ctxWithSession);
|
||||
void autoStartBroadcast(streamer, ctxWithSession);
|
||||
}
|
||||
|
||||
/** Stop the broadcast for a guild if one is live (e.g. on leave). */
|
||||
|
||||
Reference in New Issue
Block a user