# Spec: Selfbot-Viable Video Capture — manual screen-share watch command (Phase D) Status: PLANNED (not yet built) Date: 2026-09-02 Author: Hermes Related: `docs/specs/2026-08-31_video-receive-phaseC-spec.md` (auto-receive, superseded for selfbot), `gmw-ops/references/selfbot-presence-detection-limits.md`, `gmw-ops/references/discord-voice-fork-video-receive.md` ## TL;DR — the decisive finding (verified live 2026-09-02) User insists on keeping the **selfbot** (no bot-token migration). Live diagnostics prove a selfbot CANNOT auto-detect other members' camera/share because: - It never receives `VOICE_STATE_UPDATE` for other members (only its own). - `guild.members.fetch()` → 403, `GET /channels/{id}/voice-states` → 404. - No `GUILD_CREATE`, no `READY.broadcaster_user_ids` presence. - `scanExistingStreamers` + `handleVoiceStateUpdate` (the only two `startStreamWatch` triggers) are therefore both **dead on a selfbot**. - No manual watch command exists today, so even on-demand capture is impossible. → The ONE selfbot-viable path is a **manual, operator-initiated STREAM_WATCH** on a member known to be screen-sharing. Gateway op 20 (STREAM_WATCH) is **NOT gated on bot-vs-user**; the DAVE handshake to Ready+MLS was already verified live in earlier sessions. The receive/mux/segment/upload pipeline (`streamWatchReceiver.ts`) is already built and only lacks a real streamer to produce its first `.mp4`. Camera-of-others is NOT viable on a selfbot even with `unknown-ssrc` fallback: `@discordjs/voice` `parsePacket` calls `daveSession.decrypt(packet, userId)` keyed per REAL userId (vendor fork dist/index.js:2143), so a fake id selects no MLS decryptor → garbage, not H264. (The uncommitted `unknown-ssrc` change was reverted this session.) Selfbot CAN capture the OWNER's own video (its own VOICE_STATE_UPDATE + fork op12 videoSSRC are attributable), but `videoRecorder.ts` hard-skips its own id — parameterized self-capture is a follow-up, not the default. ## Goal Add a **manual watch command** so an operator can say "record 's screen share" and the gateway `startStreamWatch`s that member → DAVE watch → per-burst `.mp4` segments (mirroring voice silence split) → upload → DB `voice_recordings` → dashboard `