Addresses review of the STREAM_BROWSER / broadcast-defaults work: - SelfbotStreamer now spawns broadcast-helper.mjs on stream start and kills it on stop/self-end (alongside capture + keepalive). The ad-skip, subtitle rule and fullscreen-toolbar-hide are therefore guaranteed broadcast-wide defaults tied to the broadcast - not a manual process. Fail-open: if node/Chrome deps are absent the stream runs without the helper. Verified the helper is a child of the broadcast holder and armed. - Enforce STREAM_BROWSER at the streamer (start() returns early when screenBrowser===false), so EVERY caller including stream-hold.ts is voice-only when it's off, not just the slash command. stream-hold.ts reads STREAM_BROWSER. - Fix broadcast-helper fullscreen: resolve the window of the tab actually in HTML5 fullscreen (via its CDP targetId) instead of the first HTTP tab, so the right Chrome window is toggled when multiple windows exist. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
51 lines
2.1 KiB
TypeScript
51 lines
2.1 KiB
TypeScript
// Persistent selfbot stream holder for manual/operational testing of the
|
|
// Go-Live broadcast. Joins the voice channel, goes live, and keeps the stream
|
|
// up until stopped (SIGTERM/SIGINT) or HOLD_MS elapses. All parameters come
|
|
// from the environment (.env).
|
|
//
|
|
// bun bot/scripts/stream-test/stream-hold.ts
|
|
//
|
|
// Requires in .env: DISCORD_SELFBOT_TOKEN, DISCORD_GUILD_ID,
|
|
// DISCORD_VOICE_CHANNEL_ID. Stream params: VNC_RESOLUTION, VNC_FRAMERATE,
|
|
// VNC_BITRATE_KBPS, STREAM_HW, VNC_DISPLAY (same vars the bot uses).
|
|
import "dotenv/config";
|
|
import { SelfbotStreamer } from "../../src/stream/selfbot.ts";
|
|
|
|
const config = {
|
|
selfbotToken: process.env.DISCORD_SELFBOT_TOKEN ?? "",
|
|
vncDisplay: process.env.VNC_DISPLAY ?? ":1",
|
|
vncResolution: process.env.VNC_RESOLUTION ?? "1920x1080",
|
|
vncFramerate: parseInt(process.env.VNC_FRAMERATE ?? "60", 10),
|
|
vncBitrateKbps: parseInt(process.env.VNC_BITRATE_KBPS ?? "8000", 10),
|
|
streamHw: (process.env.STREAM_HW ?? "1") !== "0",
|
|
streamAudio: (process.env.STREAM_AUDIO ?? "1") !== "0",
|
|
streamAudioSource: process.env.STREAM_AUDIO_SOURCE ?? "@DEFAULT_MONITOR@",
|
|
screenBrowser: (process.env.STREAM_BROWSER ?? "true") !== "false",
|
|
} as any;
|
|
|
|
const guildId = process.env.DISCORD_GUILD_ID;
|
|
const voiceChannelId = process.env.DISCORD_VOICE_CHANNEL_ID;
|
|
if (!config.selfbotToken || !guildId || !voiceChannelId) {
|
|
console.error("Missing DISCORD_SELFBOT_TOKEN / DISCORD_GUILD_ID / DISCORD_VOICE_CHANNEL_ID in .env");
|
|
process.exit(1);
|
|
}
|
|
|
|
const s = new SelfbotStreamer(config);
|
|
const maxMs = parseInt(process.env.HOLD_MS ?? "7200000", 10);
|
|
let stopped = false;
|
|
const stop = async () => {
|
|
if (stopped) return;
|
|
stopped = true;
|
|
console.log("STREAM_STOPPING");
|
|
await s.stop();
|
|
console.log("STREAM_STOPPED");
|
|
process.exit(0);
|
|
};
|
|
process.on("SIGTERM", stop);
|
|
process.on("SIGINT", stop);
|
|
|
|
const r = await s.start({ guildId, voiceChannelId } as any);
|
|
console.log(`STREAM_START: ${r} active:${s.isActive()} (${config.vncResolution}@${config.vncFramerate} ${config.vncBitrateKbps}k hw=${config.streamHw})`);
|
|
setTimeout(stop, maxMs);
|
|
setInterval(() => {}, 60000);
|