[READ-ONLY] Mirror of https://github.com/flo-bit/streamplace-overlay.
flo-bit.dev/streamplace-overlay/
1.8 kB
69 lines
1#!/usr/bin/env bun
2import { appendFileSync } from 'node:fs';
3import { resolve } from 'node:path';
4
5const COLLECTION = 'place.stream.chat.message';
6const JETSTREAM_URL = 'wss://jetstream2.us-east.bsky.network/subscribe';
7
8const args = process.argv.slice(2);
9const streamerDid = args[0]?.startsWith('did:') ? args[0] : undefined;
10const outFile = resolve((streamerDid ? args[1] : args[0]) ?? 'chat.txt');
11
12const url = `${JETSTREAM_URL}?wantedCollections=${encodeURIComponent(COLLECTION)}`;
13
14type JetstreamEvent = {
15 did: string;
16 time_us: number;
17 kind: 'commit' | 'identity' | 'account';
18 commit?: {
19 rev: string;
20 operation: 'create' | 'update' | 'delete';
21 collection: string;
22 rkey: string;
23 record?: {
24 $type: string;
25 text: string;
26 streamer: string;
27 createdAt: string;
28 };
29 cid?: string;
30 };
31};
32
33function connect() {
34 console.error(
35 `[listen-chat] connecting, ${streamerDid ? `filtering streamer=${streamerDid}` : 'no streamer filter'}`,
36 );
37 const ws = new WebSocket(url);
38
39 ws.addEventListener('open', () => console.error('[listen-chat] connected'));
40
41 ws.addEventListener('message', (ev) => {
42 let msg: JetstreamEvent;
43 try {
44 msg = JSON.parse(ev.data as string);
45 } catch {
46 return;
47 }
48 const c = msg.commit;
49 if (!c || c.operation !== 'create' || c.collection !== COLLECTION) return;
50 const rec = c.record;
51 if (!rec) return;
52 if (streamerDid && rec.streamer !== streamerDid) return;
53
54 const line = `${msg.did}: ${rec.text}`;
55 appendFileSync(outFile, line + '\n');
56 console.log(line);
57 });
58
59 ws.addEventListener('close', (ev) => {
60 console.error(`[listen-chat] closed (${ev.code}); reconnecting in 2s`);
61 setTimeout(connect, 2000);
62 });
63
64 ws.addEventListener('error', (ev) => {
65 console.error('[listen-chat] error', ev);
66 });
67}
68
69connect();