A work-in-progress chat bot for Streamplace with chat overlay functionality
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Ingesting place.stream.livestream via Jetstream

+34 -24
+23 -10
utils/eventHandler.ts
··· 31 31 this.handleActorProfile(event); 32 32 break; 33 33 case "app.bsky.graph.follow": 34 - this.handleBskyFollow(event).catch(err => 35 - console.error("Error in handleBskyFollow:", err) 36 - ); 34 + this.handleBskyFollow(event).catch((err) => 35 + console.error("Error in handleBskyFollow:", err) 36 + ); 37 37 break; 38 38 case "place.stream.chat.message": 39 - this.handleChatMessage(event).catch(err => 40 - console.error("Error in handleChatMessage:", err) 41 - ); 39 + this.handleChatMessage(event).catch((err) => 40 + console.error("Error in handleChatMessage:", err) 41 + ); 42 42 break; 43 43 case "place.stream.chat.profile": 44 44 this.handleChatProfile(event); 45 45 break; 46 + case "place.stream.livestream": 47 + this.handleLivestream(event); 48 + break; 46 49 case "place.stream.live.teleport": 47 - this.handleTeleport(event).catch(err => 48 - console.error("Error in handleTeleport:", err) 49 - ); 50 + this.handleTeleport(event).catch((err) => 51 + console.error("Error in handleTeleport:", err) 52 + ); 50 53 break; 51 54 case "online.timtinkers.bot.command": 52 55 this.handleNewCommand(event); ··· 73 76 const follower = await didResolver.resolve(event.did); 74 77 const bot = botInstances.get(record.subject)!; 75 78 // Don't send chat message unless streamer is currently live 76 - if (!await bot.streamerIsLive()) return; 79 + if (!bot.streamerIsLive()) return; 77 80 const { text, facets } = new RichtextBuilder().addText( 78 81 "Thank you for the following the streamer, ", 79 82 ).addMention(follower.handle, event.did).addText("!"); ··· 255 258 bot!.getShoutoutsByAtUri().delete(uri); 256 259 bot!.getGreeted().delete(did); 257 260 } 261 + } 262 + 263 + private handleLivestream(event: CommitEvent) { 264 + if (!botInstances.get(event.did)) return; 265 + if (event.commit.operation === "delete") return; 266 + if (!is(PlaceStreamLivestream.mainSchema, event.commit.record)) return; 267 + const record = event.commit 268 + .record as PlaceStreamLivestream.Main; 269 + const bot = botInstances.get(event.did); 270 + bot!.livestream = record; 258 271 } 259 272 260 273 private async enrichMessage(
+11 -14
utils/streamplaceBot.ts
··· 28 28 private shoutoutsLoaded: boolean = false; 29 29 private hasBeenGreeted: Map<Did, Date> = new Map(); 30 30 private greetingCooldown: number = 12 * 60 * 60 * 1000; // 12 hours 31 + private livestreamRecord: PlaceStreamLivestream.Main | undefined; 31 32 32 33 /** 33 34 * Create a new StreamplaceBot ··· 215 216 } 216 217 217 218 // Check if streamer is live 218 - async streamerIsLive(): Promise<boolean> { 219 - const streamer = await didResolver.resolve(this.streamerDid); 220 - try { 221 - const { records } = await listRecords(streamer.pdsEndpoint, { 222 - repo: this.getStreamerDid(), 223 - collection: "place.stream.livestream", 224 - }); 225 - if (!records || records.length < 1) return false; 226 - const record = records[0].value as PlaceStreamLivestream.Main; 219 + streamerIsLive(): boolean { 220 + if (this.livestreamRecord) { 221 + const record = this.livestreamRecord; 227 222 if (!record.lastSeenAt) return false; 228 223 const lastSeen = new Date(record.lastSeenAt).getTime(); 229 224 const now = Date.now(); ··· 232 227 ? record.idleTimeoutSeconds * 1000 233 228 : 300 * 1000; 234 229 return (now - lastSeen) <= idleTimeoutMs; 235 - } catch (error) { 236 - console.error( 237 - "Error checking if streamer is live:", 238 - error, 239 - ); 240 230 } 241 231 return false; 242 232 } ··· 289 279 290 280 setEnabled(enabled: boolean): void { 291 281 this.enabled = enabled; 282 + } 283 + 284 + get livestream(): PlaceStreamLivestream.Main | undefined { 285 + return this.livestreamRecord; 286 + } 287 + set livestream(record: PlaceStreamLivestream.Main) { 288 + this.livestreamRecord = record; 292 289 } 293 290 } 294 291