@mulingai-npm/redis 3.36.1 → 3.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,7 @@ export type MulingstreamListenerData = {
9
9
  lastHeartbeat: number;
10
10
  language?: string;
11
11
  color?: string;
12
+ isListening?: boolean;
12
13
  };
13
14
  export declare class MulingstreamListenerManager {
14
15
  private redisClient;
@@ -29,4 +30,21 @@ export declare class MulingstreamListenerManager {
29
30
  languageBreakdown: Record<string, number>;
30
31
  }>;
31
32
  getListenerBySocketId(socketId: string): Promise<MulingstreamListenerData | null>;
33
+ /**
34
+ * Update the isListening state for a listener (audio play/pause).
35
+ */
36
+ setListeningState(listenerIdOrToken: string, isListening: boolean): Promise<MulingstreamListenerData | null>;
37
+ /**
38
+ * Returns unique languages that have at least one listener with isListening=true.
39
+ * Used by pipeline to determine which languages need TTS generation.
40
+ */
41
+ getLanguagesWithActiveListeners(roomId: string): Promise<string[]>;
42
+ /**
43
+ * Returns socket IDs for listeners of a language who have isListening=true (audio on).
44
+ */
45
+ getListeningSocketIdsByRoomLanguage(roomId: string, language: string): Promise<string[]>;
46
+ /**
47
+ * Returns socket IDs for listeners of a language who have isListening=false (audio off, reading text only).
48
+ */
49
+ getNonListeningSocketIdsByRoomLanguage(roomId: string, language: string): Promise<string[]>;
32
50
  }
@@ -45,7 +45,8 @@ class MulingstreamListenerManager {
45
45
  firstJoined: parseInt(data.firstJoined, 10),
46
46
  lastHeartbeat: parseInt(data.lastHeartbeat, 10),
47
47
  language: data.language || '',
48
- color: data.color || ''
48
+ color: data.color || '',
49
+ isListening: data.isListening === 'true'
49
50
  };
50
51
  }
51
52
  // Creates a new listener.
@@ -69,7 +70,8 @@ class MulingstreamListenerManager {
69
70
  firstJoined: listenerData.firstJoined.toString(),
70
71
  lastHeartbeat: listenerData.lastHeartbeat.toString(),
71
72
  language: (_c = listenerData.language) !== null && _c !== void 0 ? _c : '',
72
- color
73
+ color,
74
+ isListening: 'false'
73
75
  });
74
76
  // expire listener
75
77
  await this.redisClient.expire(`listener:${listenerId}`, EXPIRATION);
@@ -235,5 +237,56 @@ class MulingstreamListenerManager {
235
237
  }
236
238
  return null;
237
239
  }
240
+ /**
241
+ * Update the isListening state for a listener (audio play/pause).
242
+ */
243
+ async setListeningState(listenerIdOrToken, isListening) {
244
+ const listener = await this.getListener(listenerIdOrToken);
245
+ if (!listener) {
246
+ return null;
247
+ }
248
+ await this.redisClient.hset(`listener:${listener.listenerId}`, {
249
+ isListening: isListening.toString()
250
+ });
251
+ return { ...listener, isListening };
252
+ }
253
+ /**
254
+ * Returns unique languages that have at least one listener with isListening=true.
255
+ * Used by pipeline to determine which languages need TTS generation.
256
+ */
257
+ async getLanguagesWithActiveListeners(roomId) {
258
+ const listeners = await this.getListenersByRoom(roomId);
259
+ const languageCountMap = {};
260
+ for (const listener of listeners) {
261
+ if (!listener.language || !listener.language.trim())
262
+ continue;
263
+ if (!listener.isListening)
264
+ continue;
265
+ const lang = listener.language;
266
+ languageCountMap[lang] = (languageCountMap[lang] || 0) + 1;
267
+ }
268
+ const sortedEntries = Object.entries(languageCountMap).sort(([, countA], [, countB]) => countB - countA);
269
+ return sortedEntries.map(([language]) => language);
270
+ }
271
+ /**
272
+ * Returns socket IDs for listeners of a language who have isListening=true (audio on).
273
+ */
274
+ async getListeningSocketIdsByRoomLanguage(roomId, language) {
275
+ const listeners = await this.getListenersByRoom(roomId);
276
+ return listeners
277
+ .filter(l => l.language === language && l.isListening)
278
+ .map(l => l.socketId)
279
+ .filter((id) => !!id);
280
+ }
281
+ /**
282
+ * Returns socket IDs for listeners of a language who have isListening=false (audio off, reading text only).
283
+ */
284
+ async getNonListeningSocketIdsByRoomLanguage(roomId, language) {
285
+ const listeners = await this.getListenersByRoom(roomId);
286
+ return listeners
287
+ .filter(l => l.language === language && !l.isListening)
288
+ .map(l => l.socketId)
289
+ .filter((id) => !!id);
290
+ }
238
291
  }
239
292
  exports.MulingstreamListenerManager = MulingstreamListenerManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mulingai-npm/redis",
3
- "version": "3.36.1",
3
+ "version": "3.37.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {