@tiktool/live 1.2.0 → 1.3.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.
package/dist/index.d.mts CHANGED
@@ -69,6 +69,7 @@ interface BattleEvent extends BaseEvent {
69
69
  interface BattleArmiesEvent extends BaseEvent {
70
70
  type: 'battleArmies';
71
71
  battleId: string;
72
+ status: number;
72
73
  teams: BattleTeam[];
73
74
  }
74
75
  interface SubscribeEvent extends BaseEvent {
package/dist/index.d.ts CHANGED
@@ -69,6 +69,7 @@ interface BattleEvent extends BaseEvent {
69
69
  interface BattleArmiesEvent extends BaseEvent {
70
70
  type: 'battleArmies';
71
71
  battleId: string;
72
+ status: number;
72
73
  teams: BattleTeam[];
73
74
  }
74
75
  interface SubscribeEvent extends BaseEvent {
package/dist/index.js CHANGED
@@ -159,80 +159,147 @@ function buildAck(id) {
159
159
  function parseUser(data) {
160
160
  const f = decodeProto(data);
161
161
  const id = String(getInt(f, 1) || getStr(f, 1));
162
- const nickname = getStr(f, 3) || getStr(f, 5);
163
- const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2);
162
+ const nickname = getStr(f, 3) || getStr(f, 2);
163
+ const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2) || "";
164
164
  let profilePicture;
165
- const avatarBuf = getBytes(f, 9);
165
+ const avatarBuf = getBytes(f, 9) || getBytes(f, 3);
166
166
  if (avatarBuf) {
167
167
  try {
168
168
  const avatarFields = decodeProto(avatarBuf);
169
- const urlBuf = getBytes(avatarFields, 1);
170
- if (urlBuf) profilePicture = urlBuf.toString("utf-8");
169
+ const urlBufs = getAllBytes(avatarFields, 1);
170
+ if (urlBufs.length > 0) profilePicture = urlBufs[0].toString("utf-8");
171
171
  } catch {
172
172
  }
173
173
  }
174
- return { id, nickname, uniqueId: uniqueId || nickname || id, profilePicture };
174
+ const badges = [];
175
+ const badgeBuf = getBytes(f, 64);
176
+ if (badgeBuf) {
177
+ try {
178
+ const badgeFields = decodeProto(badgeBuf);
179
+ const badgeItems = getAllBytes(badgeFields, 21);
180
+ for (const bi of badgeItems) {
181
+ const bf = decodeProto(bi);
182
+ const name = getStr(bf, 3) || getStr(bf, 2);
183
+ if (name) badges.push(name);
184
+ }
185
+ } catch {
186
+ }
187
+ }
188
+ return {
189
+ id,
190
+ nickname,
191
+ uniqueId: uniqueId || nickname || id,
192
+ profilePicture,
193
+ badges: badges.length > 0 ? badges : void 0
194
+ };
175
195
  }
176
- function parseBattleTeam(teamBuf) {
177
- const fields = decodeProto(teamBuf);
178
- const hostUserId = String(getInt(fields, 1));
179
- const score = getInt(fields, 2);
196
+ function parseBattleTeamFromArmies(itemBuf) {
197
+ const f = decodeProto(itemBuf);
198
+ const hostUserId = String(getInt(f, 1));
199
+ let teamScore = 0;
180
200
  const users = [];
181
- const userFields = getAllBytes(fields, 3);
182
- for (const uf of userFields) {
201
+ const groups = getAllBytes(f, 2);
202
+ for (const gb of groups) {
183
203
  try {
184
- const uFields = decodeProto(uf);
185
- const userBuf = getBytes(uFields, 1);
186
- const userScore = getInt(uFields, 2);
187
- const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
188
- users.push({ user, score: userScore });
204
+ const gf = decodeProto(gb);
205
+ const points = getInt(gf, 2);
206
+ teamScore += points;
207
+ const userBufs = getAllBytes(gf, 1);
208
+ for (const ub of userBufs) {
209
+ try {
210
+ const user = parseUser(ub);
211
+ users.push({ user, score: points });
212
+ } catch {
213
+ }
214
+ }
189
215
  } catch {
190
216
  }
191
217
  }
192
- return { hostUserId, score, users };
218
+ return { hostUserId, score: teamScore, users };
193
219
  }
194
220
  function parseWebcastMessage(method, payload) {
195
221
  const f = decodeProto(payload);
196
- const base = { timestamp: Date.now(), msgId: String(getInt(f, 1) || "") };
222
+ const base = { timestamp: Date.now(), msgId: "" };
223
+ const typeBuf = getBytes(f, 1);
224
+ if (typeBuf) {
225
+ try {
226
+ const tf = decodeProto(typeBuf);
227
+ const ts = getInt(tf, 4);
228
+ if (ts) base.timestamp = ts;
229
+ } catch {
230
+ }
231
+ }
197
232
  switch (method) {
233
+ // Proto: WebcastChatMessage { MessageType type=1, User user=2, string comment=3 }
198
234
  case "WebcastChatMessage": {
199
235
  const userBuf = getBytes(f, 2);
200
236
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
201
237
  return { ...base, type: "chat", user, comment: getStr(f, 3) };
202
238
  }
239
+ // Proto: WebcastMemberMessage { User user=2, WebcastMessageEvent event=1 }
203
240
  case "WebcastMemberMessage": {
204
241
  const userBuf = getBytes(f, 2);
205
242
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
206
- return { ...base, type: "member", user, action: getInt(f, 1) };
243
+ let action = 1;
244
+ const eventBuf = getBytes(f, 1);
245
+ if (eventBuf) {
246
+ const ef = decodeProto(eventBuf);
247
+ const detailBuf = getBytes(ef, 8);
248
+ if (detailBuf) {
249
+ const df = decodeProto(detailBuf);
250
+ const label = getStr(df, 2);
251
+ if (label.includes("followed")) action = 2;
252
+ else if (label.includes("share")) action = 3;
253
+ }
254
+ }
255
+ return { ...base, type: "member", user, action };
207
256
  }
257
+ // Proto: WebcastLikeMessage { User user=5, WebcastMessageEvent event=1, int32 likeCount=2, int32 totalLikeCount=3 }
208
258
  case "WebcastLikeMessage": {
209
259
  const userBuf = getBytes(f, 5);
210
260
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
211
- return { ...base, type: "like", user, likeCount: getInt(f, 1), totalLikes: getInt(f, 2) || getInt(f, 7) };
261
+ return {
262
+ ...base,
263
+ type: "like",
264
+ user,
265
+ likeCount: getInt(f, 2),
266
+ totalLikes: getInt(f, 3)
267
+ };
212
268
  }
269
+ // Proto: WebcastGiftMessage {
270
+ // User user=7, int32 giftId=2, int32 repeatCount=5, int32 repeatEnd=9,
271
+ // GiftDetails giftDetails=15, GiftExtra giftExtra=23
272
+ // }
273
+ // GiftDetails { GiftImage giftImage=1, string giftName=16, string describe=2,
274
+ // int32 giftType=11, int32 diamondCount=12 }
275
+ // GiftExtra { uint64 timestamp=6, uint64 toUserId=8 }
213
276
  case "WebcastGiftMessage": {
214
277
  const userBuf = getBytes(f, 7);
215
278
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
216
- const giftId = getInt(f, 1);
279
+ const giftId = getInt(f, 2);
217
280
  const repeatCount = getInt(f, 5);
218
281
  const repeatEnd = getInt(f, 9) === 1;
219
- const giftType = getInt(f, 6);
220
- const groupId = getStr(f, 11);
221
- let giftName = "", diamondCount = 0;
222
- const giftInfoBuf = getBytes(f, 15);
223
- if (giftInfoBuf) {
224
- const gf = decodeProto(giftInfoBuf);
225
- giftName = getStr(gf, 1);
226
- diamondCount = getInt(gf, 5) || getInt(gf, 2);
227
- }
228
- if (!giftName) {
229
- const giftBuf3 = getBytes(f, 3);
230
- if (giftBuf3) {
231
- const gf3 = decodeProto(giftBuf3);
232
- if (!giftName) giftName = getStr(gf3, 2);
233
- if (!diamondCount) diamondCount = getInt(gf3, 5);
282
+ let giftName = "", diamondCount = 0, giftType = 0;
283
+ let giftImageUrl = "";
284
+ const detailsBuf = getBytes(f, 15);
285
+ if (detailsBuf) {
286
+ const df = decodeProto(detailsBuf);
287
+ giftName = getStr(df, 16) || getStr(df, 2);
288
+ diamondCount = getInt(df, 12);
289
+ giftType = getInt(df, 11);
290
+ const imgBuf = getBytes(df, 1);
291
+ if (imgBuf) {
292
+ const imgf = decodeProto(imgBuf);
293
+ giftImageUrl = getStr(imgf, 1);
234
294
  }
235
295
  }
296
+ let toUserId = "";
297
+ const extraBuf = getBytes(f, 23);
298
+ if (extraBuf) {
299
+ const ef = decodeProto(extraBuf);
300
+ toUserId = String(getInt(ef, 8));
301
+ }
302
+ const groupId = toUserId || getStr(f, 11);
236
303
  return {
237
304
  ...base,
238
305
  type: "gift",
@@ -247,46 +314,93 @@ function parseWebcastMessage(method, payload) {
247
314
  groupId
248
315
  };
249
316
  }
317
+ // Proto: WebcastSocialMessage { User user=2, WebcastMessageEvent event=1 }
250
318
  case "WebcastSocialMessage": {
251
319
  const userBuf = getBytes(f, 2);
252
320
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
253
- const actionInt = getInt(f, 1);
254
- const actionMap = { 1: "follow", 2: "share", 3: "like" };
255
- return { ...base, type: "social", user, action: actionMap[actionInt] || `action_${actionInt}` };
321
+ let action = "follow";
322
+ const eventBuf = getBytes(f, 1);
323
+ if (eventBuf) {
324
+ const ef = decodeProto(eventBuf);
325
+ const detailBuf = getBytes(ef, 8);
326
+ if (detailBuf) {
327
+ const df = decodeProto(detailBuf);
328
+ const label = getStr(df, 2);
329
+ if (label.includes("share")) action = "share";
330
+ else if (label.includes("follow")) action = "follow";
331
+ const displayType = getStr(df, 1);
332
+ if (displayType === "pm_mt_msg_viewer_share") action = "share";
333
+ }
334
+ }
335
+ return { ...base, type: "social", user, action };
256
336
  }
257
- case "WebcastRoomUserSeqMessage":
258
- return {
259
- ...base,
260
- type: "roomUserSeq",
261
- totalViewers: getInt(f, 1) || getInt(f, 3),
262
- viewerCount: getInt(f, 2) || getInt(f, 4)
263
- };
337
+ // Proto: WebcastRoomUserSeqMessage { int32 viewerCount=3 }
338
+ case "WebcastRoomUserSeqMessage": {
339
+ const viewerCount = getInt(f, 3) || getInt(f, 2);
340
+ const totalViewers = getInt(f, 1) || viewerCount;
341
+ return { ...base, type: "roomUserSeq", totalViewers, viewerCount };
342
+ }
343
+ // Proto: WebcastLinkMicBattle { repeated WebcastLinkMicBattleItems battleUsers=10 }
344
+ // battleUsers → { battleGroup=2 → { LinkUser user=1 } }
264
345
  case "WebcastLinkMicBattle": {
265
- const battleId = String(getInt(f, 1) || getStr(f, 1));
266
- const status = getInt(f, 2);
346
+ const battleId = String(getInt(f, 1) || "");
347
+ const status = getInt(f, 2) || 1;
267
348
  const battleDuration = getInt(f, 3);
268
349
  const teams = [];
269
- const teamBufs = getAllBytes(f, 7);
270
- for (const tb of teamBufs) {
350
+ const battleUserBufs = getAllBytes(f, 10);
351
+ for (const bub of battleUserBufs) {
271
352
  try {
272
- teams.push(parseBattleTeam(tb));
353
+ const bf = decodeProto(bub);
354
+ const groupBuf = getBytes(bf, 2);
355
+ if (groupBuf) {
356
+ const gf = decodeProto(groupBuf);
357
+ const linkUserBuf = getBytes(gf, 1);
358
+ if (linkUserBuf) {
359
+ const user = parseUser(linkUserBuf);
360
+ teams.push({
361
+ hostUserId: user.id,
362
+ score: 0,
363
+ users: [{ user, score: 0 }]
364
+ });
365
+ }
366
+ }
273
367
  } catch {
274
368
  }
275
369
  }
370
+ if (teams.length === 0) {
371
+ const teamBufs7 = getAllBytes(f, 7);
372
+ for (const tb of teamBufs7) {
373
+ try {
374
+ teams.push(parseBattleTeamFromArmies(tb));
375
+ } catch {
376
+ }
377
+ }
378
+ }
276
379
  return { ...base, type: "battle", battleId, status, battleDuration, teams };
277
380
  }
381
+ // Proto: WebcastLinkMicArmies { repeated battleItems=3, int32 battleStatus=7 }
382
+ // battleItems → { hostUserId=1, repeated battleGroups=2 }
383
+ // battleGroups → { repeated users=1, int32 points=2 }
278
384
  case "WebcastLinkMicArmies": {
279
- const battleId = String(getInt(f, 1) || getStr(f, 1));
385
+ const battleId = String(getInt(f, 1) || "");
386
+ const battleStatus = getInt(f, 7);
280
387
  const teams = [];
281
- const teamBufs = getAllBytes(f, 3);
282
- for (const tb of teamBufs) {
388
+ const itemBufs = getAllBytes(f, 3);
389
+ for (const ib of itemBufs) {
283
390
  try {
284
- teams.push(parseBattleTeam(tb));
391
+ teams.push(parseBattleTeamFromArmies(ib));
285
392
  } catch {
286
393
  }
287
394
  }
288
- return { ...base, type: "battleArmies", battleId, teams };
395
+ return {
396
+ ...base,
397
+ type: "battleArmies",
398
+ battleId,
399
+ teams,
400
+ status: battleStatus
401
+ };
289
402
  }
403
+ // Proto: WebcastSubNotifyMessage { User user=2, ... subMonth=3 }
290
404
  case "WebcastSubNotifyMessage": {
291
405
  const userBuf = getBytes(f, 2);
292
406
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
@@ -312,10 +426,18 @@ function parseWebcastMessage(method, payload) {
312
426
  const envelopeId = String(getInt(f, 1) || getStr(f, 1));
313
427
  return { ...base, type: "envelope", envelopeId, diamondCount: getInt(f, 3) };
314
428
  }
429
+ // Proto: WebcastQuestionNewMessage { MessageType type=1, QuestionDetails questionDetails=2 }
430
+ // QuestionDetails { string questionText=2, User user=5 }
315
431
  case "WebcastQuestionNewMessage": {
316
- const userBuf = getBytes(f, 2);
317
- const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
318
- return { ...base, type: "question", user, questionText: getStr(f, 3) || getStr(f, 4) };
432
+ let questionText = "", user = { id: "0", nickname: "", uniqueId: "" };
433
+ const detailBuf = getBytes(f, 2);
434
+ if (detailBuf) {
435
+ const df = decodeProto(detailBuf);
436
+ questionText = getStr(df, 2);
437
+ const userBuf = getBytes(df, 5);
438
+ if (userBuf) user = parseUser(userBuf);
439
+ }
440
+ return { ...base, type: "question", user, questionText };
319
441
  }
320
442
  case "WebcastRankUpdateMessage":
321
443
  case "WebcastHourlyRankMessage": {
@@ -335,14 +457,17 @@ function parseWebcastMessage(method, payload) {
335
457
  }
336
458
  return { ...base, type: "rankUpdate", rankType, rankList };
337
459
  }
460
+ // Proto: WebcastControlMessage { int32 action=2 }
338
461
  case "WebcastControlMessage":
339
462
  return { ...base, type: "control", action: getInt(f, 2) || getInt(f, 1) };
340
463
  case "WebcastRoomMessage":
341
464
  case "RoomMessage":
342
465
  return { ...base, type: "room", status: getInt(f, 2) };
466
+ // Proto: WebcastLiveIntroMessage { uint64 id=2, string description=4, User user=5 }
343
467
  case "WebcastLiveIntroMessage": {
344
- const roomId = String(getInt(f, 1));
345
- return { ...base, type: "liveIntro", roomId, title: getStr(f, 4) || getStr(f, 2) };
468
+ const roomId = String(getInt(f, 2));
469
+ const title = getStr(f, 4) || getStr(f, 2);
470
+ return { ...base, type: "liveIntro", roomId, title };
346
471
  }
347
472
  case "WebcastLinkMicMethod":
348
473
  case "WebcastLinkmicBattleTaskMessage": {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/proto.ts"],"sourcesContent":["export { TikTokLive } from './client.js';\r\n\r\nexport type {\r\n TikTokLiveOptions,\r\n TikTokLiveEvents,\r\n RoomInfo,\r\n LiveEvent,\r\n BaseEvent,\r\n ChatEvent,\r\n MemberEvent,\r\n LikeEvent,\r\n GiftEvent,\r\n SocialEvent,\r\n RoomUserSeqEvent,\r\n BattleEvent,\r\n BattleArmiesEvent,\r\n BattleTeam,\r\n BattleTeamUser,\r\n SubscribeEvent,\r\n EmoteChatEvent,\r\n EnvelopeEvent,\r\n QuestionEvent,\r\n ControlEvent,\r\n RoomEvent,\r\n LiveIntroEvent,\r\n RankUpdateEvent,\r\n LinkMicEvent,\r\n UnknownEvent,\r\n TikTokUser,\r\n} from './types.js';\r\n","import { EventEmitter } from 'events';\r\nimport * as http from 'http';\r\nimport * as https from 'https';\r\nimport * as zlib from 'zlib';\r\nimport WebSocket from 'ws';\r\nimport type { TikTokLiveOptions, TikTokLiveEvents, RoomInfo, LiveEvent } from './types.js';\r\nimport {\r\n decodeProto,\r\n getStr,\r\n getBytes,\r\n buildHeartbeat,\r\n buildImEnterRoom,\r\n buildAck,\r\n parseWebcastResponse,\r\n} from './proto.js';\r\n\r\nconst DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\r\nconst DEFAULT_SIGN_SERVER = 'https://api.tik.tools';\r\n\r\nfunction httpGet(url: string, headers: Record<string, string>): Promise<{\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n body: Buffer;\r\n}> {\r\n return new Promise((resolve, reject) => {\r\n const mod = url.startsWith('https') ? https : http;\r\n const req = mod.get(url, { headers }, (res) => {\r\n const chunks: Buffer[] = [];\r\n const enc = res.headers['content-encoding'];\r\n const stream = (enc === 'gzip' || enc === 'br')\r\n ? res.pipe(enc === 'br' ? zlib.createBrotliDecompress() : zlib.createGunzip())\r\n : res;\r\n stream.on('data', (c: Buffer) => chunks.push(c));\r\n stream.on('end', () => resolve({\r\n status: res.statusCode || 0,\r\n headers: res.headers,\r\n body: Buffer.concat(chunks),\r\n }));\r\n stream.on('error', reject);\r\n });\r\n req.on('error', reject);\r\n req.setTimeout(15_000, () => { req.destroy(); reject(new Error('Request timeout')); });\r\n });\r\n}\r\n\r\nfunction getWsHost(clusterRegion: string): string {\r\n if (!clusterRegion) return 'webcast-ws.tiktok.com';\r\n const r = clusterRegion.toLowerCase();\r\n if (r.startsWith('eu') || r.includes('eu')) return 'webcast-ws.eu.tiktok.com';\r\n if (r.startsWith('us') || r.includes('us')) return 'webcast-ws.us.tiktok.com';\r\n return 'webcast-ws.tiktok.com';\r\n}\r\n\r\nexport class TikTokLive extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectAttempts = 0;\r\n private intentionalClose = false;\r\n private _connected = false;\r\n private _eventCount = 0;\r\n private _roomId = '';\r\n\r\n private readonly uniqueId: string;\r\n private readonly signServerUrl: string;\r\n private readonly apiKey: string;\r\n private readonly autoReconnect: boolean;\r\n private readonly maxReconnectAttempts: number;\r\n private readonly heartbeatInterval: number;\r\n private readonly debug: boolean;\r\n\r\n constructor(options: TikTokLiveOptions) {\r\n super();\r\n this.uniqueId = options.uniqueId.replace(/^@/, '');\r\n this.signServerUrl = (options.signServerUrl || DEFAULT_SIGN_SERVER).replace(/\\/$/, '');\r\n if (!options.apiKey) throw new Error('apiKey is required. Get a free key at https://tik.tools');\r\n this.apiKey = options.apiKey;\r\n this.autoReconnect = options.autoReconnect ?? true;\r\n this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\r\n this.heartbeatInterval = options.heartbeatInterval ?? 10_000;\r\n this.debug = options.debug ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n this.intentionalClose = false;\r\n\r\n const resp = await httpGet(`https://www.tiktok.com/@${this.uniqueId}/live`, {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\r\n 'Accept-Encoding': 'gzip, deflate, br',\r\n 'Accept-Language': 'en-US,en;q=0.9',\r\n });\r\n\r\n let ttwid = '';\r\n for (const sc of [resp.headers['set-cookie'] || []].flat()) {\r\n if (typeof sc === 'string' && sc.startsWith('ttwid=')) {\r\n ttwid = sc.split(';')[0].split('=').slice(1).join('=');\r\n break;\r\n }\r\n }\r\n if (!ttwid) throw new Error('Failed to obtain session cookie');\r\n\r\n const html = resp.body.toString();\r\n let roomId = '';\r\n const sigiMatch = html.match(/id=\"SIGI_STATE\"[^>]*>([^<]+)/);\r\n if (sigiMatch) {\r\n try {\r\n const json = JSON.parse(sigiMatch[1]);\r\n const jsonStr = JSON.stringify(json);\r\n const m = jsonStr.match(/\"roomId\"\\s*:\\s*\"(\\d+)\"/);\r\n if (m) roomId = m[1];\r\n } catch { }\r\n }\r\n if (!roomId) throw new Error(`User @${this.uniqueId} is not currently live`);\r\n this._roomId = roomId;\r\n\r\n const crMatch = html.match(/\"clusterRegion\"\\s*:\\s*\"([^\"]+)\"/);\r\n const clusterRegion = crMatch ? crMatch[1] : '';\r\n const wsHost = getWsHost(clusterRegion);\r\n\r\n const wsParams = new URLSearchParams({\r\n version_code: '270000', device_platform: 'web', cookie_enabled: 'true',\r\n screen_width: '1920', screen_height: '1080', browser_language: 'en-US',\r\n browser_platform: 'Win32', browser_name: 'Mozilla',\r\n browser_version: DEFAULT_UA.split('Mozilla/')[1] || '5.0',\r\n browser_online: 'true', tz_name: Intl.DateTimeFormat().resolvedOptions().timeZone,\r\n app_name: 'tiktok_web', sup_ws_ds_opt: '1', update_version_code: '2.0.0',\r\n compress: 'gzip', webcast_language: 'en', ws_direct: '1', aid: '1988',\r\n live_id: '12', app_language: 'en', client_enter: '1', room_id: roomId,\r\n identity: 'audience', history_comment_count: '6', last_rtt: '0',\r\n heartbeat_duration: '10000', resp_content_type: 'protobuf', did_rule: '3',\r\n });\r\n\r\n const rawWsUrl = `https://${wsHost}/webcast/im/ws_proxy/ws_reuse_supplement/?${wsParams}`;\r\n\r\n const signUrl = `${this.signServerUrl}/webcast/sign_url`;\r\n\r\n let wsUrl: string;\r\n try {\r\n const signResp = await fetch(signUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': this.apiKey,\r\n },\r\n body: JSON.stringify({ url: rawWsUrl }),\r\n });\r\n const signData = await signResp.json() as Record<string, any>;\r\n\r\n if (signData.status_code === 0 && signData.data?.signed_url) {\r\n wsUrl = (signData.data.signed_url as string).replace(/^https:\\/\\//, 'wss://');\r\n } else {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n } catch {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n this.ws = new WebSocket(wsUrl, {\r\n headers: {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Cookie': `ttwid=${ttwid}`,\r\n 'Origin': 'https://www.tiktok.com',\r\n },\r\n });\r\n\r\n this.ws.on('open', () => {\r\n this._connected = true;\r\n this.reconnectAttempts = 0;\r\n\r\n this.ws!.send(buildHeartbeat(roomId));\r\n this.ws!.send(buildImEnterRoom(roomId));\r\n this.startHeartbeat(roomId);\r\n\r\n const roomInfo: RoomInfo = {\r\n roomId,\r\n wsHost,\r\n clusterRegion,\r\n connectedAt: new Date().toISOString(),\r\n };\r\n\r\n this.emit('connected');\r\n this.emit('roomInfo', roomInfo);\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (rawData: Buffer) => {\r\n this.handleFrame(Buffer.from(rawData));\r\n });\r\n\r\n this.ws.on('close', (code, reason) => {\r\n this._connected = false;\r\n this.stopHeartbeat();\r\n\r\n const reasonStr = reason?.toString() || '';\r\n this.emit('disconnected', code, reasonStr);\r\n\r\n if (!this.intentionalClose && this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30_000);\r\n setTimeout(() => this.connect().catch(e => this.emit('error', e)), delay);\r\n }\r\n });\r\n\r\n this.ws.on('error', (err) => {\r\n this.emit('error', err);\r\n if (!this._connected) reject(err);\r\n });\r\n });\r\n }\r\n\r\n disconnect(): void {\r\n this.intentionalClose = true;\r\n this.stopHeartbeat();\r\n if (this.ws) {\r\n this.ws.close(1000);\r\n this.ws = null;\r\n }\r\n this._connected = false;\r\n }\r\n\r\n get connected(): boolean {\r\n return this._connected;\r\n }\r\n\r\n get eventCount(): number {\r\n return this._eventCount;\r\n }\r\n\r\n get roomId(): string {\r\n return this._roomId;\r\n }\r\n\r\n on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.on(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.once(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.off(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n emit<K extends keyof TikTokLiveEvents>(event: K, ...args: Parameters<TikTokLiveEvents[K]>): boolean {\r\n return super.emit(event, ...args);\r\n }\r\n\r\n private handleFrame(buf: Buffer): void {\r\n try {\r\n const fields = decodeProto(buf);\r\n const idField = fields.find(f => f.fn === 2 && f.wt === 0);\r\n const id = idField ? idField.value as bigint : 0n;\r\n const type = getStr(fields, 7);\r\n const binary = getBytes(fields, 8);\r\n\r\n if (id > 0n && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildAck(id));\r\n }\r\n\r\n if (type === 'msg' && binary && binary.length > 0) {\r\n let inner = binary;\r\n if (inner.length > 2 && inner[0] === 0x1f && inner[1] === 0x8b) {\r\n try { inner = zlib.gunzipSync(inner); } catch { }\r\n }\r\n\r\n const events = parseWebcastResponse(inner);\r\n for (const evt of events) {\r\n this._eventCount++;\r\n this.emit('event', evt);\r\n this.emit(evt.type as keyof TikTokLiveEvents, evt as any);\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n private startHeartbeat(roomId: string): void {\r\n this.stopHeartbeat();\r\n this.heartbeatTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildHeartbeat(roomId));\r\n }\r\n }, this.heartbeatInterval);\r\n }\r\n\r\n private stopHeartbeat(): void {\r\n if (this.heartbeatTimer) {\r\n clearInterval(this.heartbeatTimer);\r\n this.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import type { LiveEvent, TikTokUser, BattleTeam, BattleTeamUser } from './types.js';\r\n\r\nexport function decodeVarint(buf: Buffer, offset: number): { value: number; offset: number } {\r\n let result = 0, shift = 0;\r\n while (offset < buf.length) {\r\n const byte = buf[offset++];\r\n result |= (byte & 0x7F) << shift;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n }\r\n return { value: result >>> 0, offset };\r\n}\r\n\r\nexport function decodeVarint64(buf: Buffer, offset: number): { value: bigint; offset: number } {\r\n let result = 0n, shift = 0n;\r\n while (offset < buf.length) {\r\n const byte = BigInt(buf[offset++]);\r\n result |= (byte & 0x7Fn) << shift;\r\n if ((byte & 0x80n) === 0n) break;\r\n shift += 7n;\r\n }\r\n return { value: result, offset };\r\n}\r\n\r\nexport function encodeVarint(v: number | bigint): Buffer {\r\n const bytes: number[] = [];\r\n let n = typeof v === 'bigint' ? v : BigInt(v);\r\n do {\r\n let b = Number(n & 0x7Fn);\r\n n >>= 7n;\r\n if (n > 0n) b |= 0x80;\r\n bytes.push(b);\r\n } while (n > 0n);\r\n return Buffer.from(bytes);\r\n}\r\n\r\nexport interface ProtoField {\r\n fn: number;\r\n wt: number;\r\n value: Buffer | number | bigint;\r\n}\r\n\r\nexport function encodeField(fn: number, wt: number, value: Buffer | bigint | number | string): Buffer {\r\n const tag = encodeVarint((fn << 3) | wt);\r\n if (wt === 0) {\r\n return Buffer.concat([tag, encodeVarint(typeof value === 'number' ? BigInt(value) : value as bigint)]);\r\n }\r\n const data = typeof value === 'string' ? Buffer.from(value) : value as Buffer;\r\n return Buffer.concat([tag, encodeVarint(data.length), data]);\r\n}\r\n\r\nexport function decodeProto(buf: Buffer): ProtoField[] {\r\n const fields: ProtoField[] = [];\r\n let offset = 0;\r\n while (offset < buf.length) {\r\n const tagResult = decodeVarint(buf, offset);\r\n offset = tagResult.offset;\r\n const fn = tagResult.value >> 3;\r\n const wt = tagResult.value & 7;\r\n if (wt === 0) {\r\n const r = decodeVarint64(buf, offset);\r\n offset = r.offset;\r\n fields.push({ fn, wt, value: r.value });\r\n } else if (wt === 2) {\r\n const lenR = decodeVarint(buf, offset);\r\n offset = lenR.offset;\r\n const data = buf.subarray(offset, offset + lenR.value);\r\n offset += lenR.value;\r\n fields.push({ fn, wt, value: data });\r\n } else if (wt === 1) {\r\n fields.push({ fn, wt, value: buf.readBigInt64LE(offset) });\r\n offset += 8;\r\n } else if (wt === 5) {\r\n fields.push({ fn, wt, value: BigInt(buf.readInt32LE(offset)) });\r\n offset += 4;\r\n } else {\r\n break;\r\n }\r\n }\r\n return fields;\r\n}\r\n\r\nexport function getStr(fields: ProtoField[], fn: number): string {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? (f.value as Buffer).toString('utf-8') : '';\r\n}\r\n\r\nexport function getBytes(fields: ProtoField[], fn: number): Buffer | null {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? f.value as Buffer : null;\r\n}\r\n\r\nexport function getInt(fields: ProtoField[], fn: number): number {\r\n const f = fields.find(x => x.fn === fn && x.wt === 0);\r\n return f ? Number(f.value) : 0;\r\n}\r\n\r\nexport function getAllBytes(fields: ProtoField[], fn: number): Buffer[] {\r\n return fields.filter(x => x.fn === fn && x.wt === 2).map(x => x.value as Buffer);\r\n}\r\n\r\nexport function buildHeartbeat(roomId: string): Buffer {\r\n const payload = encodeField(1, 0, BigInt(roomId));\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'hb'),\r\n encodeField(8, 2, payload),\r\n ]);\r\n}\r\n\r\nexport function buildImEnterRoom(roomId: string): Buffer {\r\n const inner = Buffer.concat([\r\n encodeField(1, 0, BigInt(roomId)),\r\n encodeField(4, 0, 12n),\r\n encodeField(5, 2, 'audience'),\r\n encodeField(6, 2, ''),\r\n encodeField(9, 2, ''),\r\n encodeField(10, 2, ''),\r\n ]);\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'im_enter_room'),\r\n encodeField(8, 2, inner),\r\n ]);\r\n}\r\n\r\nexport function buildAck(id: bigint): Buffer {\r\n return Buffer.concat([\r\n encodeField(2, 0, id),\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'ack'),\r\n ]);\r\n}\r\n\r\nfunction parseUser(data: Buffer): TikTokUser {\r\n const f = decodeProto(data);\r\n const id = String(getInt(f, 1) || getStr(f, 1));\r\n const nickname = getStr(f, 3) || getStr(f, 5);\r\n const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2);\r\n\r\n let profilePicture: string | undefined;\r\n const avatarBuf = getBytes(f, 9);\r\n if (avatarBuf) {\r\n try {\r\n const avatarFields = decodeProto(avatarBuf);\r\n const urlBuf = getBytes(avatarFields, 1);\r\n if (urlBuf) profilePicture = urlBuf.toString('utf-8');\r\n } catch { }\r\n }\r\n\r\n return { id, nickname, uniqueId: uniqueId || nickname || id, profilePicture };\r\n}\r\n\r\nfunction parseBattleTeam(teamBuf: Buffer): BattleTeam {\r\n const fields = decodeProto(teamBuf);\r\n const hostUserId = String(getInt(fields, 1));\r\n const score = getInt(fields, 2);\r\n const users: BattleTeamUser[] = [];\r\n\r\n const userFields = getAllBytes(fields, 3);\r\n for (const uf of userFields) {\r\n try {\r\n const uFields = decodeProto(uf);\r\n const userBuf = getBytes(uFields, 1);\r\n const userScore = getInt(uFields, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n users.push({ user, score: userScore });\r\n } catch { }\r\n }\r\n\r\n return { hostUserId, score, users };\r\n}\r\n\r\nexport function parseWebcastMessage(method: string, payload: Buffer): LiveEvent {\r\n const f = decodeProto(payload);\r\n const base = { timestamp: Date.now(), msgId: String(getInt(f, 1) || '') };\r\n\r\n switch (method) {\r\n case 'WebcastChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'chat' as const, user, comment: getStr(f, 3) };\r\n }\r\n\r\n case 'WebcastMemberMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'member' as const, user, action: getInt(f, 1) };\r\n }\r\n\r\n case 'WebcastLikeMessage': {\r\n const userBuf = getBytes(f, 5);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'like' as const, user, likeCount: getInt(f, 1), totalLikes: getInt(f, 2) || getInt(f, 7) };\r\n }\r\n\r\n case 'WebcastGiftMessage': {\r\n const userBuf = getBytes(f, 7);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const giftId = getInt(f, 1);\r\n const repeatCount = getInt(f, 5);\r\n const repeatEnd = getInt(f, 9) === 1;\r\n const giftType = getInt(f, 6);\r\n const groupId = getStr(f, 11);\r\n\r\n let giftName = '', diamondCount = 0;\r\n const giftInfoBuf = getBytes(f, 15);\r\n if (giftInfoBuf) {\r\n const gf = decodeProto(giftInfoBuf);\r\n giftName = getStr(gf, 1);\r\n diamondCount = getInt(gf, 5) || getInt(gf, 2);\r\n }\r\n if (!giftName) {\r\n const giftBuf3 = getBytes(f, 3);\r\n if (giftBuf3) {\r\n const gf3 = decodeProto(giftBuf3);\r\n if (!giftName) giftName = getStr(gf3, 2);\r\n if (!diamondCount) diamondCount = getInt(gf3, 5);\r\n }\r\n }\r\n\r\n return {\r\n ...base, type: 'gift' as const, user, giftId, giftName, diamondCount,\r\n repeatCount, repeatEnd, combo: repeatCount > 1 && !repeatEnd,\r\n giftType, groupId,\r\n };\r\n }\r\n\r\n case 'WebcastSocialMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const actionInt = getInt(f, 1);\r\n const actionMap: Record<number, string> = { 1: 'follow', 2: 'share', 3: 'like' };\r\n return { ...base, type: 'social' as const, user, action: actionMap[actionInt] || `action_${actionInt}` };\r\n }\r\n\r\n case 'WebcastRoomUserSeqMessage':\r\n return {\r\n ...base, type: 'roomUserSeq' as const,\r\n totalViewers: getInt(f, 1) || getInt(f, 3),\r\n viewerCount: getInt(f, 2) || getInt(f, 4),\r\n };\r\n\r\n case 'WebcastLinkMicBattle': {\r\n const battleId = String(getInt(f, 1) || getStr(f, 1));\r\n const status = getInt(f, 2);\r\n const battleDuration = getInt(f, 3);\r\n const teams: BattleTeam[] = [];\r\n const teamBufs = getAllBytes(f, 7);\r\n for (const tb of teamBufs) {\r\n try { teams.push(parseBattleTeam(tb)); } catch { }\r\n }\r\n return { ...base, type: 'battle' as const, battleId, status, battleDuration, teams };\r\n }\r\n\r\n case 'WebcastLinkMicArmies': {\r\n const battleId = String(getInt(f, 1) || getStr(f, 1));\r\n const teams: BattleTeam[] = [];\r\n const teamBufs = getAllBytes(f, 3);\r\n for (const tb of teamBufs) {\r\n try { teams.push(parseBattleTeam(tb)); } catch { }\r\n }\r\n return { ...base, type: 'battleArmies' as const, battleId, teams };\r\n }\r\n\r\n case 'WebcastSubNotifyMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'subscribe' as const, user, subMonth: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastEmoteChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let emoteId = '', emoteUrl = '';\r\n const emoteBuf = getBytes(f, 3);\r\n if (emoteBuf) {\r\n const ef = decodeProto(emoteBuf);\r\n emoteId = getStr(ef, 1);\r\n const imageBuf = getBytes(ef, 2);\r\n if (imageBuf) {\r\n const imgFields = decodeProto(imageBuf);\r\n emoteUrl = getStr(imgFields, 1);\r\n }\r\n }\r\n return { ...base, type: 'emoteChat' as const, user, emoteId, emoteUrl };\r\n }\r\n\r\n case 'WebcastEnvelopeMessage': {\r\n const envelopeId = String(getInt(f, 1) || getStr(f, 1));\r\n return { ...base, type: 'envelope' as const, envelopeId, diamondCount: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastQuestionNewMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'question' as const, user, questionText: getStr(f, 3) || getStr(f, 4) };\r\n }\r\n\r\n case 'WebcastRankUpdateMessage':\r\n case 'WebcastHourlyRankMessage': {\r\n const rankType = getStr(f, 1) || `rank_${getInt(f, 1)}`;\r\n const rankList: Array<{ user: TikTokUser; rank: number; score: number }> = [];\r\n const listBufs = getAllBytes(f, 2);\r\n for (const lb of listBufs) {\r\n try {\r\n const rf = decodeProto(lb);\r\n const userBuf = getBytes(rf, 1);\r\n const rank = getInt(rf, 2);\r\n const score = getInt(rf, 3);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n rankList.push({ user, rank, score });\r\n } catch { }\r\n }\r\n return { ...base, type: 'rankUpdate' as const, rankType, rankList };\r\n }\r\n\r\n case 'WebcastControlMessage':\r\n return { ...base, type: 'control' as const, action: getInt(f, 2) || getInt(f, 1) };\r\n\r\n case 'WebcastRoomMessage':\r\n case 'RoomMessage':\r\n return { ...base, type: 'room' as const, status: getInt(f, 2) };\r\n\r\n case 'WebcastLiveIntroMessage': {\r\n const roomId = String(getInt(f, 1));\r\n return { ...base, type: 'liveIntro' as const, roomId, title: getStr(f, 4) || getStr(f, 2) };\r\n }\r\n\r\n case 'WebcastLinkMicMethod':\r\n case 'WebcastLinkmicBattleTaskMessage': {\r\n const action = getStr(f, 1) || `action_${getInt(f, 1)}`;\r\n const users: TikTokUser[] = [];\r\n const userBufs = getAllBytes(f, 2);\r\n for (const ub of userBufs) {\r\n try { users.push(parseUser(ub)); } catch { }\r\n }\r\n return { ...base, type: 'linkMic' as const, action, users };\r\n }\r\n\r\n default:\r\n return { ...base, type: 'unknown' as const, method };\r\n }\r\n}\r\n\r\nexport function parseWebcastResponse(payload: Buffer): LiveEvent[] {\r\n const events: LiveEvent[] = [];\r\n const respFields = decodeProto(payload);\r\n\r\n for (const mf of respFields.filter(f => f.fn === 1 && f.wt === 2)) {\r\n const msgBuf = mf.value as Buffer;\r\n const msgFields = decodeProto(msgBuf);\r\n const method = getStr(msgFields, 1);\r\n const innerPayload = getBytes(msgFields, 2);\r\n if (!method || !innerPayload) continue;\r\n\r\n try {\r\n events.push(parseWebcastMessage(method, innerPayload));\r\n } catch { }\r\n }\r\n\r\n return events;\r\n}\r\n"],"mappings":"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","names":["WebSocket"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/proto.ts"],"sourcesContent":["export { TikTokLive } from './client.js';\r\n\r\nexport type {\r\n TikTokLiveOptions,\r\n TikTokLiveEvents,\r\n RoomInfo,\r\n LiveEvent,\r\n BaseEvent,\r\n ChatEvent,\r\n MemberEvent,\r\n LikeEvent,\r\n GiftEvent,\r\n SocialEvent,\r\n RoomUserSeqEvent,\r\n BattleEvent,\r\n BattleArmiesEvent,\r\n BattleTeam,\r\n BattleTeamUser,\r\n SubscribeEvent,\r\n EmoteChatEvent,\r\n EnvelopeEvent,\r\n QuestionEvent,\r\n ControlEvent,\r\n RoomEvent,\r\n LiveIntroEvent,\r\n RankUpdateEvent,\r\n LinkMicEvent,\r\n UnknownEvent,\r\n TikTokUser,\r\n} from './types.js';\r\n","import { EventEmitter } from 'events';\r\nimport * as http from 'http';\r\nimport * as https from 'https';\r\nimport * as zlib from 'zlib';\r\nimport WebSocket from 'ws';\r\nimport type { TikTokLiveOptions, TikTokLiveEvents, RoomInfo, LiveEvent } from './types.js';\r\nimport {\r\n decodeProto,\r\n getStr,\r\n getBytes,\r\n buildHeartbeat,\r\n buildImEnterRoom,\r\n buildAck,\r\n parseWebcastResponse,\r\n} from './proto.js';\r\n\r\nconst DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\r\nconst DEFAULT_SIGN_SERVER = 'https://api.tik.tools';\r\n\r\nfunction httpGet(url: string, headers: Record<string, string>): Promise<{\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n body: Buffer;\r\n}> {\r\n return new Promise((resolve, reject) => {\r\n const mod = url.startsWith('https') ? https : http;\r\n const req = mod.get(url, { headers }, (res) => {\r\n const chunks: Buffer[] = [];\r\n const enc = res.headers['content-encoding'];\r\n const stream = (enc === 'gzip' || enc === 'br')\r\n ? res.pipe(enc === 'br' ? zlib.createBrotliDecompress() : zlib.createGunzip())\r\n : res;\r\n stream.on('data', (c: Buffer) => chunks.push(c));\r\n stream.on('end', () => resolve({\r\n status: res.statusCode || 0,\r\n headers: res.headers,\r\n body: Buffer.concat(chunks),\r\n }));\r\n stream.on('error', reject);\r\n });\r\n req.on('error', reject);\r\n req.setTimeout(15_000, () => { req.destroy(); reject(new Error('Request timeout')); });\r\n });\r\n}\r\n\r\nfunction getWsHost(clusterRegion: string): string {\r\n if (!clusterRegion) return 'webcast-ws.tiktok.com';\r\n const r = clusterRegion.toLowerCase();\r\n if (r.startsWith('eu') || r.includes('eu')) return 'webcast-ws.eu.tiktok.com';\r\n if (r.startsWith('us') || r.includes('us')) return 'webcast-ws.us.tiktok.com';\r\n return 'webcast-ws.tiktok.com';\r\n}\r\n\r\nexport class TikTokLive extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectAttempts = 0;\r\n private intentionalClose = false;\r\n private _connected = false;\r\n private _eventCount = 0;\r\n private _roomId = '';\r\n\r\n private readonly uniqueId: string;\r\n private readonly signServerUrl: string;\r\n private readonly apiKey: string;\r\n private readonly autoReconnect: boolean;\r\n private readonly maxReconnectAttempts: number;\r\n private readonly heartbeatInterval: number;\r\n private readonly debug: boolean;\r\n\r\n constructor(options: TikTokLiveOptions) {\r\n super();\r\n this.uniqueId = options.uniqueId.replace(/^@/, '');\r\n this.signServerUrl = (options.signServerUrl || DEFAULT_SIGN_SERVER).replace(/\\/$/, '');\r\n if (!options.apiKey) throw new Error('apiKey is required. Get a free key at https://tik.tools');\r\n this.apiKey = options.apiKey;\r\n this.autoReconnect = options.autoReconnect ?? true;\r\n this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\r\n this.heartbeatInterval = options.heartbeatInterval ?? 10_000;\r\n this.debug = options.debug ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n this.intentionalClose = false;\r\n\r\n const resp = await httpGet(`https://www.tiktok.com/@${this.uniqueId}/live`, {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\r\n 'Accept-Encoding': 'gzip, deflate, br',\r\n 'Accept-Language': 'en-US,en;q=0.9',\r\n });\r\n\r\n let ttwid = '';\r\n for (const sc of [resp.headers['set-cookie'] || []].flat()) {\r\n if (typeof sc === 'string' && sc.startsWith('ttwid=')) {\r\n ttwid = sc.split(';')[0].split('=').slice(1).join('=');\r\n break;\r\n }\r\n }\r\n if (!ttwid) throw new Error('Failed to obtain session cookie');\r\n\r\n const html = resp.body.toString();\r\n let roomId = '';\r\n const sigiMatch = html.match(/id=\"SIGI_STATE\"[^>]*>([^<]+)/);\r\n if (sigiMatch) {\r\n try {\r\n const json = JSON.parse(sigiMatch[1]);\r\n const jsonStr = JSON.stringify(json);\r\n const m = jsonStr.match(/\"roomId\"\\s*:\\s*\"(\\d+)\"/);\r\n if (m) roomId = m[1];\r\n } catch { }\r\n }\r\n if (!roomId) throw new Error(`User @${this.uniqueId} is not currently live`);\r\n this._roomId = roomId;\r\n\r\n const crMatch = html.match(/\"clusterRegion\"\\s*:\\s*\"([^\"]+)\"/);\r\n const clusterRegion = crMatch ? crMatch[1] : '';\r\n const wsHost = getWsHost(clusterRegion);\r\n\r\n const wsParams = new URLSearchParams({\r\n version_code: '270000', device_platform: 'web', cookie_enabled: 'true',\r\n screen_width: '1920', screen_height: '1080', browser_language: 'en-US',\r\n browser_platform: 'Win32', browser_name: 'Mozilla',\r\n browser_version: DEFAULT_UA.split('Mozilla/')[1] || '5.0',\r\n browser_online: 'true', tz_name: Intl.DateTimeFormat().resolvedOptions().timeZone,\r\n app_name: 'tiktok_web', sup_ws_ds_opt: '1', update_version_code: '2.0.0',\r\n compress: 'gzip', webcast_language: 'en', ws_direct: '1', aid: '1988',\r\n live_id: '12', app_language: 'en', client_enter: '1', room_id: roomId,\r\n identity: 'audience', history_comment_count: '6', last_rtt: '0',\r\n heartbeat_duration: '10000', resp_content_type: 'protobuf', did_rule: '3',\r\n });\r\n\r\n const rawWsUrl = `https://${wsHost}/webcast/im/ws_proxy/ws_reuse_supplement/?${wsParams}`;\r\n\r\n const signUrl = `${this.signServerUrl}/webcast/sign_url`;\r\n\r\n let wsUrl: string;\r\n try {\r\n const signResp = await fetch(signUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': this.apiKey,\r\n },\r\n body: JSON.stringify({ url: rawWsUrl }),\r\n });\r\n const signData = await signResp.json() as Record<string, any>;\r\n\r\n if (signData.status_code === 0 && signData.data?.signed_url) {\r\n wsUrl = (signData.data.signed_url as string).replace(/^https:\\/\\//, 'wss://');\r\n } else {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n } catch {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n this.ws = new WebSocket(wsUrl, {\r\n headers: {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Cookie': `ttwid=${ttwid}`,\r\n 'Origin': 'https://www.tiktok.com',\r\n },\r\n });\r\n\r\n this.ws.on('open', () => {\r\n this._connected = true;\r\n this.reconnectAttempts = 0;\r\n\r\n this.ws!.send(buildHeartbeat(roomId));\r\n this.ws!.send(buildImEnterRoom(roomId));\r\n this.startHeartbeat(roomId);\r\n\r\n const roomInfo: RoomInfo = {\r\n roomId,\r\n wsHost,\r\n clusterRegion,\r\n connectedAt: new Date().toISOString(),\r\n };\r\n\r\n this.emit('connected');\r\n this.emit('roomInfo', roomInfo);\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (rawData: Buffer) => {\r\n this.handleFrame(Buffer.from(rawData));\r\n });\r\n\r\n this.ws.on('close', (code, reason) => {\r\n this._connected = false;\r\n this.stopHeartbeat();\r\n\r\n const reasonStr = reason?.toString() || '';\r\n this.emit('disconnected', code, reasonStr);\r\n\r\n if (!this.intentionalClose && this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30_000);\r\n setTimeout(() => this.connect().catch(e => this.emit('error', e)), delay);\r\n }\r\n });\r\n\r\n this.ws.on('error', (err) => {\r\n this.emit('error', err);\r\n if (!this._connected) reject(err);\r\n });\r\n });\r\n }\r\n\r\n disconnect(): void {\r\n this.intentionalClose = true;\r\n this.stopHeartbeat();\r\n if (this.ws) {\r\n this.ws.close(1000);\r\n this.ws = null;\r\n }\r\n this._connected = false;\r\n }\r\n\r\n get connected(): boolean {\r\n return this._connected;\r\n }\r\n\r\n get eventCount(): number {\r\n return this._eventCount;\r\n }\r\n\r\n get roomId(): string {\r\n return this._roomId;\r\n }\r\n\r\n on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.on(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.once(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.off(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n emit<K extends keyof TikTokLiveEvents>(event: K, ...args: Parameters<TikTokLiveEvents[K]>): boolean {\r\n return super.emit(event, ...args);\r\n }\r\n\r\n private handleFrame(buf: Buffer): void {\r\n try {\r\n const fields = decodeProto(buf);\r\n const idField = fields.find(f => f.fn === 2 && f.wt === 0);\r\n const id = idField ? idField.value as bigint : 0n;\r\n const type = getStr(fields, 7);\r\n const binary = getBytes(fields, 8);\r\n\r\n if (id > 0n && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildAck(id));\r\n }\r\n\r\n if (type === 'msg' && binary && binary.length > 0) {\r\n let inner = binary;\r\n if (inner.length > 2 && inner[0] === 0x1f && inner[1] === 0x8b) {\r\n try { inner = zlib.gunzipSync(inner); } catch { }\r\n }\r\n\r\n const events = parseWebcastResponse(inner);\r\n for (const evt of events) {\r\n this._eventCount++;\r\n this.emit('event', evt);\r\n this.emit(evt.type as keyof TikTokLiveEvents, evt as any);\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n private startHeartbeat(roomId: string): void {\r\n this.stopHeartbeat();\r\n this.heartbeatTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildHeartbeat(roomId));\r\n }\r\n }, this.heartbeatInterval);\r\n }\r\n\r\n private stopHeartbeat(): void {\r\n if (this.heartbeatTimer) {\r\n clearInterval(this.heartbeatTimer);\r\n this.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import type { LiveEvent, TikTokUser, BattleTeam, BattleTeamUser } from './types.js';\r\n\r\nexport function decodeVarint(buf: Buffer, offset: number): { value: number; offset: number } {\r\n let result = 0, shift = 0;\r\n while (offset < buf.length) {\r\n const byte = buf[offset++];\r\n result |= (byte & 0x7F) << shift;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n }\r\n return { value: result >>> 0, offset };\r\n}\r\n\r\nexport function decodeVarint64(buf: Buffer, offset: number): { value: bigint; offset: number } {\r\n let result = 0n, shift = 0n;\r\n while (offset < buf.length) {\r\n const byte = BigInt(buf[offset++]);\r\n result |= (byte & 0x7Fn) << shift;\r\n if ((byte & 0x80n) === 0n) break;\r\n shift += 7n;\r\n }\r\n return { value: result, offset };\r\n}\r\n\r\nexport function encodeVarint(v: number | bigint): Buffer {\r\n const bytes: number[] = [];\r\n let n = typeof v === 'bigint' ? v : BigInt(v);\r\n do {\r\n let b = Number(n & 0x7Fn);\r\n n >>= 7n;\r\n if (n > 0n) b |= 0x80;\r\n bytes.push(b);\r\n } while (n > 0n);\r\n return Buffer.from(bytes);\r\n}\r\n\r\nexport interface ProtoField {\r\n fn: number;\r\n wt: number;\r\n value: Buffer | number | bigint;\r\n}\r\n\r\nexport function encodeField(fn: number, wt: number, value: Buffer | bigint | number | string): Buffer {\r\n const tag = encodeVarint((fn << 3) | wt);\r\n if (wt === 0) {\r\n return Buffer.concat([tag, encodeVarint(typeof value === 'number' ? BigInt(value) : value as bigint)]);\r\n }\r\n const data = typeof value === 'string' ? Buffer.from(value) : value as Buffer;\r\n return Buffer.concat([tag, encodeVarint(data.length), data]);\r\n}\r\n\r\nexport function decodeProto(buf: Buffer): ProtoField[] {\r\n const fields: ProtoField[] = [];\r\n let offset = 0;\r\n while (offset < buf.length) {\r\n const tagResult = decodeVarint(buf, offset);\r\n offset = tagResult.offset;\r\n const fn = tagResult.value >> 3;\r\n const wt = tagResult.value & 7;\r\n if (wt === 0) {\r\n const r = decodeVarint64(buf, offset);\r\n offset = r.offset;\r\n fields.push({ fn, wt, value: r.value });\r\n } else if (wt === 2) {\r\n const lenR = decodeVarint(buf, offset);\r\n offset = lenR.offset;\r\n const data = buf.subarray(offset, offset + lenR.value);\r\n offset += lenR.value;\r\n fields.push({ fn, wt, value: data });\r\n } else if (wt === 1) {\r\n fields.push({ fn, wt, value: buf.readBigInt64LE(offset) });\r\n offset += 8;\r\n } else if (wt === 5) {\r\n fields.push({ fn, wt, value: BigInt(buf.readInt32LE(offset)) });\r\n offset += 4;\r\n } else {\r\n break;\r\n }\r\n }\r\n return fields;\r\n}\r\n\r\nexport function getStr(fields: ProtoField[], fn: number): string {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? (f.value as Buffer).toString('utf-8') : '';\r\n}\r\n\r\nexport function getBytes(fields: ProtoField[], fn: number): Buffer | null {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? f.value as Buffer : null;\r\n}\r\n\r\nexport function getInt(fields: ProtoField[], fn: number): number {\r\n const f = fields.find(x => x.fn === fn && x.wt === 0);\r\n return f ? Number(f.value) : 0;\r\n}\r\n\r\nexport function getAllBytes(fields: ProtoField[], fn: number): Buffer[] {\r\n return fields.filter(x => x.fn === fn && x.wt === 2).map(x => x.value as Buffer);\r\n}\r\n\r\nexport function buildHeartbeat(roomId: string): Buffer {\r\n const payload = encodeField(1, 0, BigInt(roomId));\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'hb'),\r\n encodeField(8, 2, payload),\r\n ]);\r\n}\r\n\r\nexport function buildImEnterRoom(roomId: string): Buffer {\r\n const inner = Buffer.concat([\r\n encodeField(1, 0, BigInt(roomId)),\r\n encodeField(4, 0, 12n),\r\n encodeField(5, 2, 'audience'),\r\n encodeField(6, 2, ''),\r\n encodeField(9, 2, ''),\r\n encodeField(10, 2, ''),\r\n ]);\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'im_enter_room'),\r\n encodeField(8, 2, inner),\r\n ]);\r\n}\r\n\r\nexport function buildAck(id: bigint): Buffer {\r\n return Buffer.concat([\r\n encodeField(2, 0, id),\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'ack'),\r\n ]);\r\n}\r\n\r\n// ── User parsing ────────────────────────────────────────────────────\r\n// Proto: User { userId=1, nickname=3, profilePicture=9, extraAttributes=22, badge=64, uniqueId=38 }\r\n// Proto: LinkUser { userId=1, nickname=2, profilePicture=3, uniqueId=4 }\r\n// Proto: ProfilePicture { repeated urls=1 }\r\n\r\nfunction parseUser(data: Buffer): TikTokUser {\r\n const f = decodeProto(data);\r\n const id = String(getInt(f, 1) || getStr(f, 1));\r\n const nickname = getStr(f, 3) || getStr(f, 2);\r\n const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2) || '';\r\n\r\n let profilePicture: string | undefined;\r\n const avatarBuf = getBytes(f, 9) || getBytes(f, 3);\r\n if (avatarBuf) {\r\n try {\r\n const avatarFields = decodeProto(avatarBuf);\r\n // ProfilePicture.urls is repeated string at field 1\r\n const urlBufs = getAllBytes(avatarFields, 1);\r\n if (urlBufs.length > 0) profilePicture = urlBufs[0].toString('utf-8');\r\n } catch { }\r\n }\r\n\r\n // Badges from field 64 → field 21 (repeated UserBadge)\r\n const badges: string[] = [];\r\n const badgeBuf = getBytes(f, 64);\r\n if (badgeBuf) {\r\n try {\r\n const badgeFields = decodeProto(badgeBuf);\r\n const badgeItems = getAllBytes(badgeFields, 21);\r\n for (const bi of badgeItems) {\r\n const bf = decodeProto(bi);\r\n const name = getStr(bf, 3) || getStr(bf, 2);\r\n if (name) badges.push(name);\r\n }\r\n } catch { }\r\n }\r\n\r\n return {\r\n id,\r\n nickname,\r\n uniqueId: uniqueId || nickname || id,\r\n profilePicture,\r\n badges: badges.length > 0 ? badges : undefined,\r\n };\r\n}\r\n\r\n// ── Battle parsing ──────────────────────────────────────────────────\r\n// Proto: WebcastLinkMicBattle { repeated battleUsers=10 }\r\n// battleUsers → WebcastLinkMicBattleItems { battleGroup=2 }\r\n// battleGroup → WebcastLinkMicBattleGroup { LinkUser user=1 }\r\n//\r\n// Proto: WebcastLinkMicArmies { repeated battleItems=3, battleStatus=7 }\r\n// battleItems → WebcastLinkMicArmiesItems { hostUserId=1, repeated battleGroups=2 }\r\n// battleGroups → WebcastLinkMicArmiesGroup { repeated users=1, points=2 }\r\n\r\nfunction parseBattleTeamFromArmies(itemBuf: Buffer): BattleTeam {\r\n const f = decodeProto(itemBuf);\r\n const hostUserId = String(getInt(f, 1));\r\n let teamScore = 0;\r\n const users: BattleTeamUser[] = [];\r\n\r\n // battleGroups at field 2\r\n const groups = getAllBytes(f, 2);\r\n for (const gb of groups) {\r\n try {\r\n const gf = decodeProto(gb);\r\n const points = getInt(gf, 2);\r\n teamScore += points;\r\n\r\n // users at field 1 (repeated)\r\n const userBufs = getAllBytes(gf, 1);\r\n for (const ub of userBufs) {\r\n try {\r\n const user = parseUser(ub);\r\n users.push({ user, score: points });\r\n } catch { }\r\n }\r\n } catch { }\r\n }\r\n\r\n return { hostUserId, score: teamScore, users };\r\n}\r\n\r\n// ── Message-specific parsers ────────────────────────────────────────\r\n\r\nexport function parseWebcastMessage(method: string, payload: Buffer): LiveEvent {\r\n const f = decodeProto(payload);\r\n const base = { timestamp: Date.now(), msgId: '' };\r\n\r\n // Try to extract msgId from MessageType (field 1 submessage, field 4 = timestamp)\r\n const typeBuf = getBytes(f, 1);\r\n if (typeBuf) {\r\n try {\r\n const tf = decodeProto(typeBuf);\r\n const ts = getInt(tf, 4);\r\n if (ts) base.timestamp = ts;\r\n } catch { }\r\n }\r\n\r\n switch (method) {\r\n // Proto: WebcastChatMessage { MessageType type=1, User user=2, string comment=3 }\r\n case 'WebcastChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'chat' as const, user, comment: getStr(f, 3) };\r\n }\r\n\r\n // Proto: WebcastMemberMessage { User user=2, WebcastMessageEvent event=1 }\r\n case 'WebcastMemberMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let action = 1;\r\n const eventBuf = getBytes(f, 1);\r\n if (eventBuf) {\r\n const ef = decodeProto(eventBuf);\r\n const detailBuf = getBytes(ef, 8);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n const label = getStr(df, 2);\r\n if (label.includes('followed')) action = 2;\r\n else if (label.includes('share')) action = 3;\r\n }\r\n }\r\n return { ...base, type: 'member' as const, user, action };\r\n }\r\n\r\n // Proto: WebcastLikeMessage { User user=5, WebcastMessageEvent event=1, int32 likeCount=2, int32 totalLikeCount=3 }\r\n case 'WebcastLikeMessage': {\r\n const userBuf = getBytes(f, 5);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return {\r\n ...base, type: 'like' as const, user,\r\n likeCount: getInt(f, 2),\r\n totalLikes: getInt(f, 3),\r\n };\r\n }\r\n\r\n // Proto: WebcastGiftMessage {\r\n // User user=7, int32 giftId=2, int32 repeatCount=5, int32 repeatEnd=9,\r\n // GiftDetails giftDetails=15, GiftExtra giftExtra=23\r\n // }\r\n // GiftDetails { GiftImage giftImage=1, string giftName=16, string describe=2,\r\n // int32 giftType=11, int32 diamondCount=12 }\r\n // GiftExtra { uint64 timestamp=6, uint64 toUserId=8 }\r\n case 'WebcastGiftMessage': {\r\n const userBuf = getBytes(f, 7);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const giftId = getInt(f, 2);\r\n const repeatCount = getInt(f, 5);\r\n const repeatEnd = getInt(f, 9) === 1;\r\n\r\n let giftName = '', diamondCount = 0, giftType = 0;\r\n let giftImageUrl = '';\r\n const detailsBuf = getBytes(f, 15);\r\n if (detailsBuf) {\r\n const df = decodeProto(detailsBuf);\r\n giftName = getStr(df, 16) || getStr(df, 2);\r\n diamondCount = getInt(df, 12);\r\n giftType = getInt(df, 11);\r\n\r\n const imgBuf = getBytes(df, 1);\r\n if (imgBuf) {\r\n const imgf = decodeProto(imgBuf);\r\n giftImageUrl = getStr(imgf, 1);\r\n }\r\n }\r\n\r\n let toUserId = '';\r\n const extraBuf = getBytes(f, 23);\r\n if (extraBuf) {\r\n const ef = decodeProto(extraBuf);\r\n toUserId = String(getInt(ef, 8));\r\n }\r\n\r\n const groupId = toUserId || getStr(f, 11);\r\n\r\n return {\r\n ...base, type: 'gift' as const, user, giftId, giftName, diamondCount,\r\n repeatCount, repeatEnd, combo: repeatCount > 1 && !repeatEnd,\r\n giftType, groupId,\r\n };\r\n }\r\n\r\n // Proto: WebcastSocialMessage { User user=2, WebcastMessageEvent event=1 }\r\n case 'WebcastSocialMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let action = 'follow';\r\n const eventBuf = getBytes(f, 1);\r\n if (eventBuf) {\r\n const ef = decodeProto(eventBuf);\r\n const detailBuf = getBytes(ef, 8);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n const label = getStr(df, 2);\r\n if (label.includes('share')) action = 'share';\r\n else if (label.includes('follow')) action = 'follow';\r\n const displayType = getStr(df, 1);\r\n if (displayType === 'pm_mt_msg_viewer_share') action = 'share';\r\n }\r\n }\r\n return { ...base, type: 'social' as const, user, action };\r\n }\r\n\r\n // Proto: WebcastRoomUserSeqMessage { int32 viewerCount=3 }\r\n case 'WebcastRoomUserSeqMessage': {\r\n const viewerCount = getInt(f, 3) || getInt(f, 2);\r\n const totalViewers = getInt(f, 1) || viewerCount;\r\n return { ...base, type: 'roomUserSeq' as const, totalViewers, viewerCount };\r\n }\r\n\r\n // Proto: WebcastLinkMicBattle { repeated WebcastLinkMicBattleItems battleUsers=10 }\r\n // battleUsers → { battleGroup=2 → { LinkUser user=1 } }\r\n case 'WebcastLinkMicBattle': {\r\n const battleId = String(getInt(f, 1) || '');\r\n const status = getInt(f, 2) || 1;\r\n const battleDuration = getInt(f, 3);\r\n const teams: BattleTeam[] = [];\r\n\r\n // battleUsers at field 10\r\n const battleUserBufs = getAllBytes(f, 10);\r\n for (const bub of battleUserBufs) {\r\n try {\r\n const bf = decodeProto(bub);\r\n const groupBuf = getBytes(bf, 2);\r\n if (groupBuf) {\r\n const gf = decodeProto(groupBuf);\r\n const linkUserBuf = getBytes(gf, 1);\r\n if (linkUserBuf) {\r\n const user = parseUser(linkUserBuf);\r\n teams.push({\r\n hostUserId: user.id,\r\n score: 0,\r\n users: [{ user, score: 0 }],\r\n });\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n // Also try field 7 as fallback (some message versions)\r\n if (teams.length === 0) {\r\n const teamBufs7 = getAllBytes(f, 7);\r\n for (const tb of teamBufs7) {\r\n try {\r\n teams.push(parseBattleTeamFromArmies(tb));\r\n } catch { }\r\n }\r\n }\r\n\r\n return { ...base, type: 'battle' as const, battleId, status, battleDuration, teams };\r\n }\r\n\r\n // Proto: WebcastLinkMicArmies { repeated battleItems=3, int32 battleStatus=7 }\r\n // battleItems → { hostUserId=1, repeated battleGroups=2 }\r\n // battleGroups → { repeated users=1, int32 points=2 }\r\n case 'WebcastLinkMicArmies': {\r\n const battleId = String(getInt(f, 1) || '');\r\n const battleStatus = getInt(f, 7);\r\n const teams: BattleTeam[] = [];\r\n\r\n const itemBufs = getAllBytes(f, 3);\r\n for (const ib of itemBufs) {\r\n try {\r\n teams.push(parseBattleTeamFromArmies(ib));\r\n } catch { }\r\n }\r\n\r\n return {\r\n ...base, type: 'battleArmies' as const, battleId, teams,\r\n status: battleStatus,\r\n };\r\n }\r\n\r\n // Proto: WebcastSubNotifyMessage { User user=2, ... subMonth=3 }\r\n case 'WebcastSubNotifyMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'subscribe' as const, user, subMonth: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastEmoteChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let emoteId = '', emoteUrl = '';\r\n const emoteBuf = getBytes(f, 3);\r\n if (emoteBuf) {\r\n const ef = decodeProto(emoteBuf);\r\n emoteId = getStr(ef, 1);\r\n const imageBuf = getBytes(ef, 2);\r\n if (imageBuf) {\r\n const imgFields = decodeProto(imageBuf);\r\n emoteUrl = getStr(imgFields, 1);\r\n }\r\n }\r\n return { ...base, type: 'emoteChat' as const, user, emoteId, emoteUrl };\r\n }\r\n\r\n case 'WebcastEnvelopeMessage': {\r\n const envelopeId = String(getInt(f, 1) || getStr(f, 1));\r\n return { ...base, type: 'envelope' as const, envelopeId, diamondCount: getInt(f, 3) };\r\n }\r\n\r\n // Proto: WebcastQuestionNewMessage { MessageType type=1, QuestionDetails questionDetails=2 }\r\n // QuestionDetails { string questionText=2, User user=5 }\r\n case 'WebcastQuestionNewMessage': {\r\n let questionText = '', user: TikTokUser = { id: '0', nickname: '', uniqueId: '' };\r\n const detailBuf = getBytes(f, 2);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n questionText = getStr(df, 2);\r\n const userBuf = getBytes(df, 5);\r\n if (userBuf) user = parseUser(userBuf);\r\n }\r\n return { ...base, type: 'question' as const, user, questionText };\r\n }\r\n\r\n case 'WebcastRankUpdateMessage':\r\n case 'WebcastHourlyRankMessage': {\r\n const rankType = getStr(f, 1) || `rank_${getInt(f, 1)}`;\r\n const rankList: Array<{ user: TikTokUser; rank: number; score: number }> = [];\r\n const listBufs = getAllBytes(f, 2);\r\n for (const lb of listBufs) {\r\n try {\r\n const rf = decodeProto(lb);\r\n const userBuf = getBytes(rf, 1);\r\n const rank = getInt(rf, 2);\r\n const score = getInt(rf, 3);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n rankList.push({ user, rank, score });\r\n } catch { }\r\n }\r\n return { ...base, type: 'rankUpdate' as const, rankType, rankList };\r\n }\r\n\r\n // Proto: WebcastControlMessage { int32 action=2 }\r\n case 'WebcastControlMessage':\r\n return { ...base, type: 'control' as const, action: getInt(f, 2) || getInt(f, 1) };\r\n\r\n case 'WebcastRoomMessage':\r\n case 'RoomMessage':\r\n return { ...base, type: 'room' as const, status: getInt(f, 2) };\r\n\r\n // Proto: WebcastLiveIntroMessage { uint64 id=2, string description=4, User user=5 }\r\n case 'WebcastLiveIntroMessage': {\r\n const roomId = String(getInt(f, 2));\r\n const title = getStr(f, 4) || getStr(f, 2);\r\n return { ...base, type: 'liveIntro' as const, roomId, title };\r\n }\r\n\r\n case 'WebcastLinkMicMethod':\r\n case 'WebcastLinkmicBattleTaskMessage': {\r\n const action = getStr(f, 1) || `action_${getInt(f, 1)}`;\r\n const users: TikTokUser[] = [];\r\n const userBufs = getAllBytes(f, 2);\r\n for (const ub of userBufs) {\r\n try { users.push(parseUser(ub)); } catch { }\r\n }\r\n return { ...base, type: 'linkMic' as const, action, users };\r\n }\r\n\r\n default:\r\n return { ...base, type: 'unknown' as const, method };\r\n }\r\n}\r\n\r\nexport function parseWebcastResponse(payload: Buffer): LiveEvent[] {\r\n const events: LiveEvent[] = [];\r\n const respFields = decodeProto(payload);\r\n\r\n for (const mf of respFields.filter(f => f.fn === 1 && f.wt === 2)) {\r\n const msgBuf = mf.value as Buffer;\r\n const msgFields = decodeProto(msgBuf);\r\n const method = getStr(msgFields, 1);\r\n const innerPayload = getBytes(msgFields, 2);\r\n if (!method || !innerPayload) continue;\r\n\r\n try {\r\n events.push(parseWebcastMessage(method, innerPayload));\r\n } catch { }\r\n }\r\n\r\n return events;\r\n}\r\n"],"mappings":"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","names":["WebSocket"]}
package/dist/index.mjs CHANGED
@@ -123,80 +123,147 @@ function buildAck(id) {
123
123
  function parseUser(data) {
124
124
  const f = decodeProto(data);
125
125
  const id = String(getInt(f, 1) || getStr(f, 1));
126
- const nickname = getStr(f, 3) || getStr(f, 5);
127
- const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2);
126
+ const nickname = getStr(f, 3) || getStr(f, 2);
127
+ const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2) || "";
128
128
  let profilePicture;
129
- const avatarBuf = getBytes(f, 9);
129
+ const avatarBuf = getBytes(f, 9) || getBytes(f, 3);
130
130
  if (avatarBuf) {
131
131
  try {
132
132
  const avatarFields = decodeProto(avatarBuf);
133
- const urlBuf = getBytes(avatarFields, 1);
134
- if (urlBuf) profilePicture = urlBuf.toString("utf-8");
133
+ const urlBufs = getAllBytes(avatarFields, 1);
134
+ if (urlBufs.length > 0) profilePicture = urlBufs[0].toString("utf-8");
135
135
  } catch {
136
136
  }
137
137
  }
138
- return { id, nickname, uniqueId: uniqueId || nickname || id, profilePicture };
138
+ const badges = [];
139
+ const badgeBuf = getBytes(f, 64);
140
+ if (badgeBuf) {
141
+ try {
142
+ const badgeFields = decodeProto(badgeBuf);
143
+ const badgeItems = getAllBytes(badgeFields, 21);
144
+ for (const bi of badgeItems) {
145
+ const bf = decodeProto(bi);
146
+ const name = getStr(bf, 3) || getStr(bf, 2);
147
+ if (name) badges.push(name);
148
+ }
149
+ } catch {
150
+ }
151
+ }
152
+ return {
153
+ id,
154
+ nickname,
155
+ uniqueId: uniqueId || nickname || id,
156
+ profilePicture,
157
+ badges: badges.length > 0 ? badges : void 0
158
+ };
139
159
  }
140
- function parseBattleTeam(teamBuf) {
141
- const fields = decodeProto(teamBuf);
142
- const hostUserId = String(getInt(fields, 1));
143
- const score = getInt(fields, 2);
160
+ function parseBattleTeamFromArmies(itemBuf) {
161
+ const f = decodeProto(itemBuf);
162
+ const hostUserId = String(getInt(f, 1));
163
+ let teamScore = 0;
144
164
  const users = [];
145
- const userFields = getAllBytes(fields, 3);
146
- for (const uf of userFields) {
165
+ const groups = getAllBytes(f, 2);
166
+ for (const gb of groups) {
147
167
  try {
148
- const uFields = decodeProto(uf);
149
- const userBuf = getBytes(uFields, 1);
150
- const userScore = getInt(uFields, 2);
151
- const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
152
- users.push({ user, score: userScore });
168
+ const gf = decodeProto(gb);
169
+ const points = getInt(gf, 2);
170
+ teamScore += points;
171
+ const userBufs = getAllBytes(gf, 1);
172
+ for (const ub of userBufs) {
173
+ try {
174
+ const user = parseUser(ub);
175
+ users.push({ user, score: points });
176
+ } catch {
177
+ }
178
+ }
153
179
  } catch {
154
180
  }
155
181
  }
156
- return { hostUserId, score, users };
182
+ return { hostUserId, score: teamScore, users };
157
183
  }
158
184
  function parseWebcastMessage(method, payload) {
159
185
  const f = decodeProto(payload);
160
- const base = { timestamp: Date.now(), msgId: String(getInt(f, 1) || "") };
186
+ const base = { timestamp: Date.now(), msgId: "" };
187
+ const typeBuf = getBytes(f, 1);
188
+ if (typeBuf) {
189
+ try {
190
+ const tf = decodeProto(typeBuf);
191
+ const ts = getInt(tf, 4);
192
+ if (ts) base.timestamp = ts;
193
+ } catch {
194
+ }
195
+ }
161
196
  switch (method) {
197
+ // Proto: WebcastChatMessage { MessageType type=1, User user=2, string comment=3 }
162
198
  case "WebcastChatMessage": {
163
199
  const userBuf = getBytes(f, 2);
164
200
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
165
201
  return { ...base, type: "chat", user, comment: getStr(f, 3) };
166
202
  }
203
+ // Proto: WebcastMemberMessage { User user=2, WebcastMessageEvent event=1 }
167
204
  case "WebcastMemberMessage": {
168
205
  const userBuf = getBytes(f, 2);
169
206
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
170
- return { ...base, type: "member", user, action: getInt(f, 1) };
207
+ let action = 1;
208
+ const eventBuf = getBytes(f, 1);
209
+ if (eventBuf) {
210
+ const ef = decodeProto(eventBuf);
211
+ const detailBuf = getBytes(ef, 8);
212
+ if (detailBuf) {
213
+ const df = decodeProto(detailBuf);
214
+ const label = getStr(df, 2);
215
+ if (label.includes("followed")) action = 2;
216
+ else if (label.includes("share")) action = 3;
217
+ }
218
+ }
219
+ return { ...base, type: "member", user, action };
171
220
  }
221
+ // Proto: WebcastLikeMessage { User user=5, WebcastMessageEvent event=1, int32 likeCount=2, int32 totalLikeCount=3 }
172
222
  case "WebcastLikeMessage": {
173
223
  const userBuf = getBytes(f, 5);
174
224
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
175
- return { ...base, type: "like", user, likeCount: getInt(f, 1), totalLikes: getInt(f, 2) || getInt(f, 7) };
225
+ return {
226
+ ...base,
227
+ type: "like",
228
+ user,
229
+ likeCount: getInt(f, 2),
230
+ totalLikes: getInt(f, 3)
231
+ };
176
232
  }
233
+ // Proto: WebcastGiftMessage {
234
+ // User user=7, int32 giftId=2, int32 repeatCount=5, int32 repeatEnd=9,
235
+ // GiftDetails giftDetails=15, GiftExtra giftExtra=23
236
+ // }
237
+ // GiftDetails { GiftImage giftImage=1, string giftName=16, string describe=2,
238
+ // int32 giftType=11, int32 diamondCount=12 }
239
+ // GiftExtra { uint64 timestamp=6, uint64 toUserId=8 }
177
240
  case "WebcastGiftMessage": {
178
241
  const userBuf = getBytes(f, 7);
179
242
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
180
- const giftId = getInt(f, 1);
243
+ const giftId = getInt(f, 2);
181
244
  const repeatCount = getInt(f, 5);
182
245
  const repeatEnd = getInt(f, 9) === 1;
183
- const giftType = getInt(f, 6);
184
- const groupId = getStr(f, 11);
185
- let giftName = "", diamondCount = 0;
186
- const giftInfoBuf = getBytes(f, 15);
187
- if (giftInfoBuf) {
188
- const gf = decodeProto(giftInfoBuf);
189
- giftName = getStr(gf, 1);
190
- diamondCount = getInt(gf, 5) || getInt(gf, 2);
191
- }
192
- if (!giftName) {
193
- const giftBuf3 = getBytes(f, 3);
194
- if (giftBuf3) {
195
- const gf3 = decodeProto(giftBuf3);
196
- if (!giftName) giftName = getStr(gf3, 2);
197
- if (!diamondCount) diamondCount = getInt(gf3, 5);
246
+ let giftName = "", diamondCount = 0, giftType = 0;
247
+ let giftImageUrl = "";
248
+ const detailsBuf = getBytes(f, 15);
249
+ if (detailsBuf) {
250
+ const df = decodeProto(detailsBuf);
251
+ giftName = getStr(df, 16) || getStr(df, 2);
252
+ diamondCount = getInt(df, 12);
253
+ giftType = getInt(df, 11);
254
+ const imgBuf = getBytes(df, 1);
255
+ if (imgBuf) {
256
+ const imgf = decodeProto(imgBuf);
257
+ giftImageUrl = getStr(imgf, 1);
198
258
  }
199
259
  }
260
+ let toUserId = "";
261
+ const extraBuf = getBytes(f, 23);
262
+ if (extraBuf) {
263
+ const ef = decodeProto(extraBuf);
264
+ toUserId = String(getInt(ef, 8));
265
+ }
266
+ const groupId = toUserId || getStr(f, 11);
200
267
  return {
201
268
  ...base,
202
269
  type: "gift",
@@ -211,46 +278,93 @@ function parseWebcastMessage(method, payload) {
211
278
  groupId
212
279
  };
213
280
  }
281
+ // Proto: WebcastSocialMessage { User user=2, WebcastMessageEvent event=1 }
214
282
  case "WebcastSocialMessage": {
215
283
  const userBuf = getBytes(f, 2);
216
284
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
217
- const actionInt = getInt(f, 1);
218
- const actionMap = { 1: "follow", 2: "share", 3: "like" };
219
- return { ...base, type: "social", user, action: actionMap[actionInt] || `action_${actionInt}` };
285
+ let action = "follow";
286
+ const eventBuf = getBytes(f, 1);
287
+ if (eventBuf) {
288
+ const ef = decodeProto(eventBuf);
289
+ const detailBuf = getBytes(ef, 8);
290
+ if (detailBuf) {
291
+ const df = decodeProto(detailBuf);
292
+ const label = getStr(df, 2);
293
+ if (label.includes("share")) action = "share";
294
+ else if (label.includes("follow")) action = "follow";
295
+ const displayType = getStr(df, 1);
296
+ if (displayType === "pm_mt_msg_viewer_share") action = "share";
297
+ }
298
+ }
299
+ return { ...base, type: "social", user, action };
220
300
  }
221
- case "WebcastRoomUserSeqMessage":
222
- return {
223
- ...base,
224
- type: "roomUserSeq",
225
- totalViewers: getInt(f, 1) || getInt(f, 3),
226
- viewerCount: getInt(f, 2) || getInt(f, 4)
227
- };
301
+ // Proto: WebcastRoomUserSeqMessage { int32 viewerCount=3 }
302
+ case "WebcastRoomUserSeqMessage": {
303
+ const viewerCount = getInt(f, 3) || getInt(f, 2);
304
+ const totalViewers = getInt(f, 1) || viewerCount;
305
+ return { ...base, type: "roomUserSeq", totalViewers, viewerCount };
306
+ }
307
+ // Proto: WebcastLinkMicBattle { repeated WebcastLinkMicBattleItems battleUsers=10 }
308
+ // battleUsers → { battleGroup=2 → { LinkUser user=1 } }
228
309
  case "WebcastLinkMicBattle": {
229
- const battleId = String(getInt(f, 1) || getStr(f, 1));
230
- const status = getInt(f, 2);
310
+ const battleId = String(getInt(f, 1) || "");
311
+ const status = getInt(f, 2) || 1;
231
312
  const battleDuration = getInt(f, 3);
232
313
  const teams = [];
233
- const teamBufs = getAllBytes(f, 7);
234
- for (const tb of teamBufs) {
314
+ const battleUserBufs = getAllBytes(f, 10);
315
+ for (const bub of battleUserBufs) {
235
316
  try {
236
- teams.push(parseBattleTeam(tb));
317
+ const bf = decodeProto(bub);
318
+ const groupBuf = getBytes(bf, 2);
319
+ if (groupBuf) {
320
+ const gf = decodeProto(groupBuf);
321
+ const linkUserBuf = getBytes(gf, 1);
322
+ if (linkUserBuf) {
323
+ const user = parseUser(linkUserBuf);
324
+ teams.push({
325
+ hostUserId: user.id,
326
+ score: 0,
327
+ users: [{ user, score: 0 }]
328
+ });
329
+ }
330
+ }
237
331
  } catch {
238
332
  }
239
333
  }
334
+ if (teams.length === 0) {
335
+ const teamBufs7 = getAllBytes(f, 7);
336
+ for (const tb of teamBufs7) {
337
+ try {
338
+ teams.push(parseBattleTeamFromArmies(tb));
339
+ } catch {
340
+ }
341
+ }
342
+ }
240
343
  return { ...base, type: "battle", battleId, status, battleDuration, teams };
241
344
  }
345
+ // Proto: WebcastLinkMicArmies { repeated battleItems=3, int32 battleStatus=7 }
346
+ // battleItems → { hostUserId=1, repeated battleGroups=2 }
347
+ // battleGroups → { repeated users=1, int32 points=2 }
242
348
  case "WebcastLinkMicArmies": {
243
- const battleId = String(getInt(f, 1) || getStr(f, 1));
349
+ const battleId = String(getInt(f, 1) || "");
350
+ const battleStatus = getInt(f, 7);
244
351
  const teams = [];
245
- const teamBufs = getAllBytes(f, 3);
246
- for (const tb of teamBufs) {
352
+ const itemBufs = getAllBytes(f, 3);
353
+ for (const ib of itemBufs) {
247
354
  try {
248
- teams.push(parseBattleTeam(tb));
355
+ teams.push(parseBattleTeamFromArmies(ib));
249
356
  } catch {
250
357
  }
251
358
  }
252
- return { ...base, type: "battleArmies", battleId, teams };
359
+ return {
360
+ ...base,
361
+ type: "battleArmies",
362
+ battleId,
363
+ teams,
364
+ status: battleStatus
365
+ };
253
366
  }
367
+ // Proto: WebcastSubNotifyMessage { User user=2, ... subMonth=3 }
254
368
  case "WebcastSubNotifyMessage": {
255
369
  const userBuf = getBytes(f, 2);
256
370
  const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
@@ -276,10 +390,18 @@ function parseWebcastMessage(method, payload) {
276
390
  const envelopeId = String(getInt(f, 1) || getStr(f, 1));
277
391
  return { ...base, type: "envelope", envelopeId, diamondCount: getInt(f, 3) };
278
392
  }
393
+ // Proto: WebcastQuestionNewMessage { MessageType type=1, QuestionDetails questionDetails=2 }
394
+ // QuestionDetails { string questionText=2, User user=5 }
279
395
  case "WebcastQuestionNewMessage": {
280
- const userBuf = getBytes(f, 2);
281
- const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
282
- return { ...base, type: "question", user, questionText: getStr(f, 3) || getStr(f, 4) };
396
+ let questionText = "", user = { id: "0", nickname: "", uniqueId: "" };
397
+ const detailBuf = getBytes(f, 2);
398
+ if (detailBuf) {
399
+ const df = decodeProto(detailBuf);
400
+ questionText = getStr(df, 2);
401
+ const userBuf = getBytes(df, 5);
402
+ if (userBuf) user = parseUser(userBuf);
403
+ }
404
+ return { ...base, type: "question", user, questionText };
283
405
  }
284
406
  case "WebcastRankUpdateMessage":
285
407
  case "WebcastHourlyRankMessage": {
@@ -299,14 +421,17 @@ function parseWebcastMessage(method, payload) {
299
421
  }
300
422
  return { ...base, type: "rankUpdate", rankType, rankList };
301
423
  }
424
+ // Proto: WebcastControlMessage { int32 action=2 }
302
425
  case "WebcastControlMessage":
303
426
  return { ...base, type: "control", action: getInt(f, 2) || getInt(f, 1) };
304
427
  case "WebcastRoomMessage":
305
428
  case "RoomMessage":
306
429
  return { ...base, type: "room", status: getInt(f, 2) };
430
+ // Proto: WebcastLiveIntroMessage { uint64 id=2, string description=4, User user=5 }
307
431
  case "WebcastLiveIntroMessage": {
308
- const roomId = String(getInt(f, 1));
309
- return { ...base, type: "liveIntro", roomId, title: getStr(f, 4) || getStr(f, 2) };
432
+ const roomId = String(getInt(f, 2));
433
+ const title = getStr(f, 4) || getStr(f, 2);
434
+ return { ...base, type: "liveIntro", roomId, title };
310
435
  }
311
436
  case "WebcastLinkMicMethod":
312
437
  case "WebcastLinkmicBattleTaskMessage": {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/proto.ts"],"sourcesContent":["import { EventEmitter } from 'events';\r\nimport * as http from 'http';\r\nimport * as https from 'https';\r\nimport * as zlib from 'zlib';\r\nimport WebSocket from 'ws';\r\nimport type { TikTokLiveOptions, TikTokLiveEvents, RoomInfo, LiveEvent } from './types.js';\r\nimport {\r\n decodeProto,\r\n getStr,\r\n getBytes,\r\n buildHeartbeat,\r\n buildImEnterRoom,\r\n buildAck,\r\n parseWebcastResponse,\r\n} from './proto.js';\r\n\r\nconst DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\r\nconst DEFAULT_SIGN_SERVER = 'https://api.tik.tools';\r\n\r\nfunction httpGet(url: string, headers: Record<string, string>): Promise<{\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n body: Buffer;\r\n}> {\r\n return new Promise((resolve, reject) => {\r\n const mod = url.startsWith('https') ? https : http;\r\n const req = mod.get(url, { headers }, (res) => {\r\n const chunks: Buffer[] = [];\r\n const enc = res.headers['content-encoding'];\r\n const stream = (enc === 'gzip' || enc === 'br')\r\n ? res.pipe(enc === 'br' ? zlib.createBrotliDecompress() : zlib.createGunzip())\r\n : res;\r\n stream.on('data', (c: Buffer) => chunks.push(c));\r\n stream.on('end', () => resolve({\r\n status: res.statusCode || 0,\r\n headers: res.headers,\r\n body: Buffer.concat(chunks),\r\n }));\r\n stream.on('error', reject);\r\n });\r\n req.on('error', reject);\r\n req.setTimeout(15_000, () => { req.destroy(); reject(new Error('Request timeout')); });\r\n });\r\n}\r\n\r\nfunction getWsHost(clusterRegion: string): string {\r\n if (!clusterRegion) return 'webcast-ws.tiktok.com';\r\n const r = clusterRegion.toLowerCase();\r\n if (r.startsWith('eu') || r.includes('eu')) return 'webcast-ws.eu.tiktok.com';\r\n if (r.startsWith('us') || r.includes('us')) return 'webcast-ws.us.tiktok.com';\r\n return 'webcast-ws.tiktok.com';\r\n}\r\n\r\nexport class TikTokLive extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectAttempts = 0;\r\n private intentionalClose = false;\r\n private _connected = false;\r\n private _eventCount = 0;\r\n private _roomId = '';\r\n\r\n private readonly uniqueId: string;\r\n private readonly signServerUrl: string;\r\n private readonly apiKey: string;\r\n private readonly autoReconnect: boolean;\r\n private readonly maxReconnectAttempts: number;\r\n private readonly heartbeatInterval: number;\r\n private readonly debug: boolean;\r\n\r\n constructor(options: TikTokLiveOptions) {\r\n super();\r\n this.uniqueId = options.uniqueId.replace(/^@/, '');\r\n this.signServerUrl = (options.signServerUrl || DEFAULT_SIGN_SERVER).replace(/\\/$/, '');\r\n if (!options.apiKey) throw new Error('apiKey is required. Get a free key at https://tik.tools');\r\n this.apiKey = options.apiKey;\r\n this.autoReconnect = options.autoReconnect ?? true;\r\n this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\r\n this.heartbeatInterval = options.heartbeatInterval ?? 10_000;\r\n this.debug = options.debug ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n this.intentionalClose = false;\r\n\r\n const resp = await httpGet(`https://www.tiktok.com/@${this.uniqueId}/live`, {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\r\n 'Accept-Encoding': 'gzip, deflate, br',\r\n 'Accept-Language': 'en-US,en;q=0.9',\r\n });\r\n\r\n let ttwid = '';\r\n for (const sc of [resp.headers['set-cookie'] || []].flat()) {\r\n if (typeof sc === 'string' && sc.startsWith('ttwid=')) {\r\n ttwid = sc.split(';')[0].split('=').slice(1).join('=');\r\n break;\r\n }\r\n }\r\n if (!ttwid) throw new Error('Failed to obtain session cookie');\r\n\r\n const html = resp.body.toString();\r\n let roomId = '';\r\n const sigiMatch = html.match(/id=\"SIGI_STATE\"[^>]*>([^<]+)/);\r\n if (sigiMatch) {\r\n try {\r\n const json = JSON.parse(sigiMatch[1]);\r\n const jsonStr = JSON.stringify(json);\r\n const m = jsonStr.match(/\"roomId\"\\s*:\\s*\"(\\d+)\"/);\r\n if (m) roomId = m[1];\r\n } catch { }\r\n }\r\n if (!roomId) throw new Error(`User @${this.uniqueId} is not currently live`);\r\n this._roomId = roomId;\r\n\r\n const crMatch = html.match(/\"clusterRegion\"\\s*:\\s*\"([^\"]+)\"/);\r\n const clusterRegion = crMatch ? crMatch[1] : '';\r\n const wsHost = getWsHost(clusterRegion);\r\n\r\n const wsParams = new URLSearchParams({\r\n version_code: '270000', device_platform: 'web', cookie_enabled: 'true',\r\n screen_width: '1920', screen_height: '1080', browser_language: 'en-US',\r\n browser_platform: 'Win32', browser_name: 'Mozilla',\r\n browser_version: DEFAULT_UA.split('Mozilla/')[1] || '5.0',\r\n browser_online: 'true', tz_name: Intl.DateTimeFormat().resolvedOptions().timeZone,\r\n app_name: 'tiktok_web', sup_ws_ds_opt: '1', update_version_code: '2.0.0',\r\n compress: 'gzip', webcast_language: 'en', ws_direct: '1', aid: '1988',\r\n live_id: '12', app_language: 'en', client_enter: '1', room_id: roomId,\r\n identity: 'audience', history_comment_count: '6', last_rtt: '0',\r\n heartbeat_duration: '10000', resp_content_type: 'protobuf', did_rule: '3',\r\n });\r\n\r\n const rawWsUrl = `https://${wsHost}/webcast/im/ws_proxy/ws_reuse_supplement/?${wsParams}`;\r\n\r\n const signUrl = `${this.signServerUrl}/webcast/sign_url`;\r\n\r\n let wsUrl: string;\r\n try {\r\n const signResp = await fetch(signUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': this.apiKey,\r\n },\r\n body: JSON.stringify({ url: rawWsUrl }),\r\n });\r\n const signData = await signResp.json() as Record<string, any>;\r\n\r\n if (signData.status_code === 0 && signData.data?.signed_url) {\r\n wsUrl = (signData.data.signed_url as string).replace(/^https:\\/\\//, 'wss://');\r\n } else {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n } catch {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n this.ws = new WebSocket(wsUrl, {\r\n headers: {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Cookie': `ttwid=${ttwid}`,\r\n 'Origin': 'https://www.tiktok.com',\r\n },\r\n });\r\n\r\n this.ws.on('open', () => {\r\n this._connected = true;\r\n this.reconnectAttempts = 0;\r\n\r\n this.ws!.send(buildHeartbeat(roomId));\r\n this.ws!.send(buildImEnterRoom(roomId));\r\n this.startHeartbeat(roomId);\r\n\r\n const roomInfo: RoomInfo = {\r\n roomId,\r\n wsHost,\r\n clusterRegion,\r\n connectedAt: new Date().toISOString(),\r\n };\r\n\r\n this.emit('connected');\r\n this.emit('roomInfo', roomInfo);\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (rawData: Buffer) => {\r\n this.handleFrame(Buffer.from(rawData));\r\n });\r\n\r\n this.ws.on('close', (code, reason) => {\r\n this._connected = false;\r\n this.stopHeartbeat();\r\n\r\n const reasonStr = reason?.toString() || '';\r\n this.emit('disconnected', code, reasonStr);\r\n\r\n if (!this.intentionalClose && this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30_000);\r\n setTimeout(() => this.connect().catch(e => this.emit('error', e)), delay);\r\n }\r\n });\r\n\r\n this.ws.on('error', (err) => {\r\n this.emit('error', err);\r\n if (!this._connected) reject(err);\r\n });\r\n });\r\n }\r\n\r\n disconnect(): void {\r\n this.intentionalClose = true;\r\n this.stopHeartbeat();\r\n if (this.ws) {\r\n this.ws.close(1000);\r\n this.ws = null;\r\n }\r\n this._connected = false;\r\n }\r\n\r\n get connected(): boolean {\r\n return this._connected;\r\n }\r\n\r\n get eventCount(): number {\r\n return this._eventCount;\r\n }\r\n\r\n get roomId(): string {\r\n return this._roomId;\r\n }\r\n\r\n on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.on(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.once(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.off(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n emit<K extends keyof TikTokLiveEvents>(event: K, ...args: Parameters<TikTokLiveEvents[K]>): boolean {\r\n return super.emit(event, ...args);\r\n }\r\n\r\n private handleFrame(buf: Buffer): void {\r\n try {\r\n const fields = decodeProto(buf);\r\n const idField = fields.find(f => f.fn === 2 && f.wt === 0);\r\n const id = idField ? idField.value as bigint : 0n;\r\n const type = getStr(fields, 7);\r\n const binary = getBytes(fields, 8);\r\n\r\n if (id > 0n && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildAck(id));\r\n }\r\n\r\n if (type === 'msg' && binary && binary.length > 0) {\r\n let inner = binary;\r\n if (inner.length > 2 && inner[0] === 0x1f && inner[1] === 0x8b) {\r\n try { inner = zlib.gunzipSync(inner); } catch { }\r\n }\r\n\r\n const events = parseWebcastResponse(inner);\r\n for (const evt of events) {\r\n this._eventCount++;\r\n this.emit('event', evt);\r\n this.emit(evt.type as keyof TikTokLiveEvents, evt as any);\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n private startHeartbeat(roomId: string): void {\r\n this.stopHeartbeat();\r\n this.heartbeatTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildHeartbeat(roomId));\r\n }\r\n }, this.heartbeatInterval);\r\n }\r\n\r\n private stopHeartbeat(): void {\r\n if (this.heartbeatTimer) {\r\n clearInterval(this.heartbeatTimer);\r\n this.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import type { LiveEvent, TikTokUser, BattleTeam, BattleTeamUser } from './types.js';\r\n\r\nexport function decodeVarint(buf: Buffer, offset: number): { value: number; offset: number } {\r\n let result = 0, shift = 0;\r\n while (offset < buf.length) {\r\n const byte = buf[offset++];\r\n result |= (byte & 0x7F) << shift;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n }\r\n return { value: result >>> 0, offset };\r\n}\r\n\r\nexport function decodeVarint64(buf: Buffer, offset: number): { value: bigint; offset: number } {\r\n let result = 0n, shift = 0n;\r\n while (offset < buf.length) {\r\n const byte = BigInt(buf[offset++]);\r\n result |= (byte & 0x7Fn) << shift;\r\n if ((byte & 0x80n) === 0n) break;\r\n shift += 7n;\r\n }\r\n return { value: result, offset };\r\n}\r\n\r\nexport function encodeVarint(v: number | bigint): Buffer {\r\n const bytes: number[] = [];\r\n let n = typeof v === 'bigint' ? v : BigInt(v);\r\n do {\r\n let b = Number(n & 0x7Fn);\r\n n >>= 7n;\r\n if (n > 0n) b |= 0x80;\r\n bytes.push(b);\r\n } while (n > 0n);\r\n return Buffer.from(bytes);\r\n}\r\n\r\nexport interface ProtoField {\r\n fn: number;\r\n wt: number;\r\n value: Buffer | number | bigint;\r\n}\r\n\r\nexport function encodeField(fn: number, wt: number, value: Buffer | bigint | number | string): Buffer {\r\n const tag = encodeVarint((fn << 3) | wt);\r\n if (wt === 0) {\r\n return Buffer.concat([tag, encodeVarint(typeof value === 'number' ? BigInt(value) : value as bigint)]);\r\n }\r\n const data = typeof value === 'string' ? Buffer.from(value) : value as Buffer;\r\n return Buffer.concat([tag, encodeVarint(data.length), data]);\r\n}\r\n\r\nexport function decodeProto(buf: Buffer): ProtoField[] {\r\n const fields: ProtoField[] = [];\r\n let offset = 0;\r\n while (offset < buf.length) {\r\n const tagResult = decodeVarint(buf, offset);\r\n offset = tagResult.offset;\r\n const fn = tagResult.value >> 3;\r\n const wt = tagResult.value & 7;\r\n if (wt === 0) {\r\n const r = decodeVarint64(buf, offset);\r\n offset = r.offset;\r\n fields.push({ fn, wt, value: r.value });\r\n } else if (wt === 2) {\r\n const lenR = decodeVarint(buf, offset);\r\n offset = lenR.offset;\r\n const data = buf.subarray(offset, offset + lenR.value);\r\n offset += lenR.value;\r\n fields.push({ fn, wt, value: data });\r\n } else if (wt === 1) {\r\n fields.push({ fn, wt, value: buf.readBigInt64LE(offset) });\r\n offset += 8;\r\n } else if (wt === 5) {\r\n fields.push({ fn, wt, value: BigInt(buf.readInt32LE(offset)) });\r\n offset += 4;\r\n } else {\r\n break;\r\n }\r\n }\r\n return fields;\r\n}\r\n\r\nexport function getStr(fields: ProtoField[], fn: number): string {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? (f.value as Buffer).toString('utf-8') : '';\r\n}\r\n\r\nexport function getBytes(fields: ProtoField[], fn: number): Buffer | null {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? f.value as Buffer : null;\r\n}\r\n\r\nexport function getInt(fields: ProtoField[], fn: number): number {\r\n const f = fields.find(x => x.fn === fn && x.wt === 0);\r\n return f ? Number(f.value) : 0;\r\n}\r\n\r\nexport function getAllBytes(fields: ProtoField[], fn: number): Buffer[] {\r\n return fields.filter(x => x.fn === fn && x.wt === 2).map(x => x.value as Buffer);\r\n}\r\n\r\nexport function buildHeartbeat(roomId: string): Buffer {\r\n const payload = encodeField(1, 0, BigInt(roomId));\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'hb'),\r\n encodeField(8, 2, payload),\r\n ]);\r\n}\r\n\r\nexport function buildImEnterRoom(roomId: string): Buffer {\r\n const inner = Buffer.concat([\r\n encodeField(1, 0, BigInt(roomId)),\r\n encodeField(4, 0, 12n),\r\n encodeField(5, 2, 'audience'),\r\n encodeField(6, 2, ''),\r\n encodeField(9, 2, ''),\r\n encodeField(10, 2, ''),\r\n ]);\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'im_enter_room'),\r\n encodeField(8, 2, inner),\r\n ]);\r\n}\r\n\r\nexport function buildAck(id: bigint): Buffer {\r\n return Buffer.concat([\r\n encodeField(2, 0, id),\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'ack'),\r\n ]);\r\n}\r\n\r\nfunction parseUser(data: Buffer): TikTokUser {\r\n const f = decodeProto(data);\r\n const id = String(getInt(f, 1) || getStr(f, 1));\r\n const nickname = getStr(f, 3) || getStr(f, 5);\r\n const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2);\r\n\r\n let profilePicture: string | undefined;\r\n const avatarBuf = getBytes(f, 9);\r\n if (avatarBuf) {\r\n try {\r\n const avatarFields = decodeProto(avatarBuf);\r\n const urlBuf = getBytes(avatarFields, 1);\r\n if (urlBuf) profilePicture = urlBuf.toString('utf-8');\r\n } catch { }\r\n }\r\n\r\n return { id, nickname, uniqueId: uniqueId || nickname || id, profilePicture };\r\n}\r\n\r\nfunction parseBattleTeam(teamBuf: Buffer): BattleTeam {\r\n const fields = decodeProto(teamBuf);\r\n const hostUserId = String(getInt(fields, 1));\r\n const score = getInt(fields, 2);\r\n const users: BattleTeamUser[] = [];\r\n\r\n const userFields = getAllBytes(fields, 3);\r\n for (const uf of userFields) {\r\n try {\r\n const uFields = decodeProto(uf);\r\n const userBuf = getBytes(uFields, 1);\r\n const userScore = getInt(uFields, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n users.push({ user, score: userScore });\r\n } catch { }\r\n }\r\n\r\n return { hostUserId, score, users };\r\n}\r\n\r\nexport function parseWebcastMessage(method: string, payload: Buffer): LiveEvent {\r\n const f = decodeProto(payload);\r\n const base = { timestamp: Date.now(), msgId: String(getInt(f, 1) || '') };\r\n\r\n switch (method) {\r\n case 'WebcastChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'chat' as const, user, comment: getStr(f, 3) };\r\n }\r\n\r\n case 'WebcastMemberMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'member' as const, user, action: getInt(f, 1) };\r\n }\r\n\r\n case 'WebcastLikeMessage': {\r\n const userBuf = getBytes(f, 5);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'like' as const, user, likeCount: getInt(f, 1), totalLikes: getInt(f, 2) || getInt(f, 7) };\r\n }\r\n\r\n case 'WebcastGiftMessage': {\r\n const userBuf = getBytes(f, 7);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const giftId = getInt(f, 1);\r\n const repeatCount = getInt(f, 5);\r\n const repeatEnd = getInt(f, 9) === 1;\r\n const giftType = getInt(f, 6);\r\n const groupId = getStr(f, 11);\r\n\r\n let giftName = '', diamondCount = 0;\r\n const giftInfoBuf = getBytes(f, 15);\r\n if (giftInfoBuf) {\r\n const gf = decodeProto(giftInfoBuf);\r\n giftName = getStr(gf, 1);\r\n diamondCount = getInt(gf, 5) || getInt(gf, 2);\r\n }\r\n if (!giftName) {\r\n const giftBuf3 = getBytes(f, 3);\r\n if (giftBuf3) {\r\n const gf3 = decodeProto(giftBuf3);\r\n if (!giftName) giftName = getStr(gf3, 2);\r\n if (!diamondCount) diamondCount = getInt(gf3, 5);\r\n }\r\n }\r\n\r\n return {\r\n ...base, type: 'gift' as const, user, giftId, giftName, diamondCount,\r\n repeatCount, repeatEnd, combo: repeatCount > 1 && !repeatEnd,\r\n giftType, groupId,\r\n };\r\n }\r\n\r\n case 'WebcastSocialMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const actionInt = getInt(f, 1);\r\n const actionMap: Record<number, string> = { 1: 'follow', 2: 'share', 3: 'like' };\r\n return { ...base, type: 'social' as const, user, action: actionMap[actionInt] || `action_${actionInt}` };\r\n }\r\n\r\n case 'WebcastRoomUserSeqMessage':\r\n return {\r\n ...base, type: 'roomUserSeq' as const,\r\n totalViewers: getInt(f, 1) || getInt(f, 3),\r\n viewerCount: getInt(f, 2) || getInt(f, 4),\r\n };\r\n\r\n case 'WebcastLinkMicBattle': {\r\n const battleId = String(getInt(f, 1) || getStr(f, 1));\r\n const status = getInt(f, 2);\r\n const battleDuration = getInt(f, 3);\r\n const teams: BattleTeam[] = [];\r\n const teamBufs = getAllBytes(f, 7);\r\n for (const tb of teamBufs) {\r\n try { teams.push(parseBattleTeam(tb)); } catch { }\r\n }\r\n return { ...base, type: 'battle' as const, battleId, status, battleDuration, teams };\r\n }\r\n\r\n case 'WebcastLinkMicArmies': {\r\n const battleId = String(getInt(f, 1) || getStr(f, 1));\r\n const teams: BattleTeam[] = [];\r\n const teamBufs = getAllBytes(f, 3);\r\n for (const tb of teamBufs) {\r\n try { teams.push(parseBattleTeam(tb)); } catch { }\r\n }\r\n return { ...base, type: 'battleArmies' as const, battleId, teams };\r\n }\r\n\r\n case 'WebcastSubNotifyMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'subscribe' as const, user, subMonth: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastEmoteChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let emoteId = '', emoteUrl = '';\r\n const emoteBuf = getBytes(f, 3);\r\n if (emoteBuf) {\r\n const ef = decodeProto(emoteBuf);\r\n emoteId = getStr(ef, 1);\r\n const imageBuf = getBytes(ef, 2);\r\n if (imageBuf) {\r\n const imgFields = decodeProto(imageBuf);\r\n emoteUrl = getStr(imgFields, 1);\r\n }\r\n }\r\n return { ...base, type: 'emoteChat' as const, user, emoteId, emoteUrl };\r\n }\r\n\r\n case 'WebcastEnvelopeMessage': {\r\n const envelopeId = String(getInt(f, 1) || getStr(f, 1));\r\n return { ...base, type: 'envelope' as const, envelopeId, diamondCount: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastQuestionNewMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'question' as const, user, questionText: getStr(f, 3) || getStr(f, 4) };\r\n }\r\n\r\n case 'WebcastRankUpdateMessage':\r\n case 'WebcastHourlyRankMessage': {\r\n const rankType = getStr(f, 1) || `rank_${getInt(f, 1)}`;\r\n const rankList: Array<{ user: TikTokUser; rank: number; score: number }> = [];\r\n const listBufs = getAllBytes(f, 2);\r\n for (const lb of listBufs) {\r\n try {\r\n const rf = decodeProto(lb);\r\n const userBuf = getBytes(rf, 1);\r\n const rank = getInt(rf, 2);\r\n const score = getInt(rf, 3);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n rankList.push({ user, rank, score });\r\n } catch { }\r\n }\r\n return { ...base, type: 'rankUpdate' as const, rankType, rankList };\r\n }\r\n\r\n case 'WebcastControlMessage':\r\n return { ...base, type: 'control' as const, action: getInt(f, 2) || getInt(f, 1) };\r\n\r\n case 'WebcastRoomMessage':\r\n case 'RoomMessage':\r\n return { ...base, type: 'room' as const, status: getInt(f, 2) };\r\n\r\n case 'WebcastLiveIntroMessage': {\r\n const roomId = String(getInt(f, 1));\r\n return { ...base, type: 'liveIntro' as const, roomId, title: getStr(f, 4) || getStr(f, 2) };\r\n }\r\n\r\n case 'WebcastLinkMicMethod':\r\n case 'WebcastLinkmicBattleTaskMessage': {\r\n const action = getStr(f, 1) || `action_${getInt(f, 1)}`;\r\n const users: TikTokUser[] = [];\r\n const userBufs = getAllBytes(f, 2);\r\n for (const ub of userBufs) {\r\n try { users.push(parseUser(ub)); } catch { }\r\n }\r\n return { ...base, type: 'linkMic' as const, action, users };\r\n }\r\n\r\n default:\r\n return { ...base, type: 'unknown' as const, method };\r\n }\r\n}\r\n\r\nexport function parseWebcastResponse(payload: Buffer): LiveEvent[] {\r\n const events: LiveEvent[] = [];\r\n const respFields = decodeProto(payload);\r\n\r\n for (const mf of respFields.filter(f => f.fn === 1 && f.wt === 2)) {\r\n const msgBuf = mf.value as Buffer;\r\n const msgFields = decodeProto(msgBuf);\r\n const method = getStr(msgFields, 1);\r\n const innerPayload = getBytes(msgFields, 2);\r\n if (!method || !innerPayload) continue;\r\n\r\n try {\r\n events.push(parseWebcastMessage(method, innerPayload));\r\n } catch { }\r\n }\r\n\r\n return events;\r\n}\r\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,YAAY,UAAU;AACtB,YAAY,WAAW;AACvB,YAAY,UAAU;AACtB,OAAO,eAAe;;;ACFf,SAAS,aAAa,KAAa,QAAmD;AACzF,MAAI,SAAS,GAAG,QAAQ;AACxB,SAAO,SAAS,IAAI,QAAQ;AACxB,UAAM,OAAO,IAAI,QAAQ;AACzB,eAAW,OAAO,QAAS;AAC3B,SAAK,OAAO,SAAU,EAAG;AACzB,aAAS;AAAA,EACb;AACA,SAAO,EAAE,OAAO,WAAW,GAAG,OAAO;AACzC;AAEO,SAAS,eAAe,KAAa,QAAmD;AAC3F,MAAI,SAAS,IAAI,QAAQ;AACzB,SAAO,SAAS,IAAI,QAAQ;AACxB,UAAM,OAAO,OAAO,IAAI,QAAQ,CAAC;AACjC,eAAW,OAAO,UAAU;AAC5B,SAAK,OAAO,WAAW,GAAI;AAC3B,aAAS;AAAA,EACb;AACA,SAAO,EAAE,OAAO,QAAQ,OAAO;AACnC;AAEO,SAAS,aAAa,GAA4B;AACrD,QAAM,QAAkB,CAAC;AACzB,MAAI,IAAI,OAAO,MAAM,WAAW,IAAI,OAAO,CAAC;AAC5C,KAAG;AACC,QAAI,IAAI,OAAO,IAAI,KAAK;AACxB,UAAM;AACN,QAAI,IAAI,GAAI,MAAK;AACjB,UAAM,KAAK,CAAC;AAAA,EAChB,SAAS,IAAI;AACb,SAAO,OAAO,KAAK,KAAK;AAC5B;AAQO,SAAS,YAAY,IAAY,IAAY,OAAkD;AAClG,QAAM,MAAM,aAAc,MAAM,IAAK,EAAE;AACvC,MAAI,OAAO,GAAG;AACV,WAAO,OAAO,OAAO,CAAC,KAAK,aAAa,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI,KAAe,CAAC,CAAC;AAAA,EACzG;AACA,QAAM,OAAO,OAAO,UAAU,WAAW,OAAO,KAAK,KAAK,IAAI;AAC9D,SAAO,OAAO,OAAO,CAAC,KAAK,aAAa,KAAK,MAAM,GAAG,IAAI,CAAC;AAC/D;AAEO,SAAS,YAAY,KAA2B;AACnD,QAAM,SAAuB,CAAC;AAC9B,MAAI,SAAS;AACb,SAAO,SAAS,IAAI,QAAQ;AACxB,UAAM,YAAY,aAAa,KAAK,MAAM;AAC1C,aAAS,UAAU;AACnB,UAAM,KAAK,UAAU,SAAS;AAC9B,UAAM,KAAK,UAAU,QAAQ;AAC7B,QAAI,OAAO,GAAG;AACV,YAAM,IAAI,eAAe,KAAK,MAAM;AACpC,eAAS,EAAE;AACX,aAAO,KAAK,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,CAAC;AAAA,IAC1C,WAAW,OAAO,GAAG;AACjB,YAAM,OAAO,aAAa,KAAK,MAAM;AACrC,eAAS,KAAK;AACd,YAAM,OAAO,IAAI,SAAS,QAAQ,SAAS,KAAK,KAAK;AACrD,gBAAU,KAAK;AACf,aAAO,KAAK,EAAE,IAAI,IAAI,OAAO,KAAK,CAAC;AAAA,IACvC,WAAW,OAAO,GAAG;AACjB,aAAO,KAAK,EAAE,IAAI,IAAI,OAAO,IAAI,eAAe,MAAM,EAAE,CAAC;AACzD,gBAAU;AAAA,IACd,WAAW,OAAO,GAAG;AACjB,aAAO,KAAK,EAAE,IAAI,IAAI,OAAO,OAAO,IAAI,YAAY,MAAM,CAAC,EAAE,CAAC;AAC9D,gBAAU;AAAA,IACd,OAAO;AACH;AAAA,IACJ;AAAA,EACJ;AACA,SAAO;AACX;AAEO,SAAS,OAAO,QAAsB,IAAoB;AAC7D,QAAM,IAAI,OAAO,KAAK,OAAK,EAAE,OAAO,MAAM,EAAE,OAAO,CAAC;AACpD,SAAO,IAAK,EAAE,MAAiB,SAAS,OAAO,IAAI;AACvD;AAEO,SAAS,SAAS,QAAsB,IAA2B;AACtE,QAAM,IAAI,OAAO,KAAK,OAAK,EAAE,OAAO,MAAM,EAAE,OAAO,CAAC;AACpD,SAAO,IAAI,EAAE,QAAkB;AACnC;AAEO,SAAS,OAAO,QAAsB,IAAoB;AAC7D,QAAM,IAAI,OAAO,KAAK,OAAK,EAAE,OAAO,MAAM,EAAE,OAAO,CAAC;AACpD,SAAO,IAAI,OAAO,EAAE,KAAK,IAAI;AACjC;AAEO,SAAS,YAAY,QAAsB,IAAsB;AACpE,SAAO,OAAO,OAAO,OAAK,EAAE,OAAO,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,OAAK,EAAE,KAAe;AACnF;AAEO,SAAS,eAAe,QAAwB;AACnD,QAAM,UAAU,YAAY,GAAG,GAAG,OAAO,MAAM,CAAC;AAChD,SAAO,OAAO,OAAO;AAAA,IACjB,YAAY,GAAG,GAAG,IAAI;AAAA,IACtB,YAAY,GAAG,GAAG,IAAI;AAAA,IACtB,YAAY,GAAG,GAAG,OAAO;AAAA,EAC7B,CAAC;AACL;AAEO,SAAS,iBAAiB,QAAwB;AACrD,QAAM,QAAQ,OAAO,OAAO;AAAA,IACxB,YAAY,GAAG,GAAG,OAAO,MAAM,CAAC;AAAA,IAChC,YAAY,GAAG,GAAG,GAAG;AAAA,IACrB,YAAY,GAAG,GAAG,UAAU;AAAA,IAC5B,YAAY,GAAG,GAAG,EAAE;AAAA,IACpB,YAAY,GAAG,GAAG,EAAE;AAAA,IACpB,YAAY,IAAI,GAAG,EAAE;AAAA,EACzB,CAAC;AACD,SAAO,OAAO,OAAO;AAAA,IACjB,YAAY,GAAG,GAAG,IAAI;AAAA,IACtB,YAAY,GAAG,GAAG,eAAe;AAAA,IACjC,YAAY,GAAG,GAAG,KAAK;AAAA,EAC3B,CAAC;AACL;AAEO,SAAS,SAAS,IAAoB;AACzC,SAAO,OAAO,OAAO;AAAA,IACjB,YAAY,GAAG,GAAG,EAAE;AAAA,IACpB,YAAY,GAAG,GAAG,IAAI;AAAA,IACtB,YAAY,GAAG,GAAG,KAAK;AAAA,EAC3B,CAAC;AACL;AAEA,SAAS,UAAU,MAA0B;AACzC,QAAM,IAAI,YAAY,IAAI;AAC1B,QAAM,KAAK,OAAO,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AAC9C,QAAM,WAAW,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC;AAC5C,QAAM,WAAW,OAAO,GAAG,EAAE,KAAK,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC;AAE7D,MAAI;AACJ,QAAM,YAAY,SAAS,GAAG,CAAC;AAC/B,MAAI,WAAW;AACX,QAAI;AACA,YAAM,eAAe,YAAY,SAAS;AAC1C,YAAM,SAAS,SAAS,cAAc,CAAC;AACvC,UAAI,OAAQ,kBAAiB,OAAO,SAAS,OAAO;AAAA,IACxD,QAAQ;AAAA,IAAE;AAAA,EACd;AAEA,SAAO,EAAE,IAAI,UAAU,UAAU,YAAY,YAAY,IAAI,eAAe;AAChF;AAEA,SAAS,gBAAgB,SAA6B;AAClD,QAAM,SAAS,YAAY,OAAO;AAClC,QAAM,aAAa,OAAO,OAAO,QAAQ,CAAC,CAAC;AAC3C,QAAM,QAAQ,OAAO,QAAQ,CAAC;AAC9B,QAAM,QAA0B,CAAC;AAEjC,QAAM,aAAa,YAAY,QAAQ,CAAC;AACxC,aAAW,MAAM,YAAY;AACzB,QAAI;AACA,YAAM,UAAU,YAAY,EAAE;AAC9B,YAAM,UAAU,SAAS,SAAS,CAAC;AACnC,YAAM,YAAY,OAAO,SAAS,CAAC;AACnC,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,YAAM,KAAK,EAAE,MAAM,OAAO,UAAU,CAAC;AAAA,IACzC,QAAQ;AAAA,IAAE;AAAA,EACd;AAEA,SAAO,EAAE,YAAY,OAAO,MAAM;AACtC;AAEO,SAAS,oBAAoB,QAAgB,SAA4B;AAC5E,QAAM,IAAI,YAAY,OAAO;AAC7B,QAAM,OAAO,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,OAAO,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;AAExE,UAAQ,QAAQ;AAAA,IACZ,KAAK,sBAAsB;AACvB,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,MAAM,QAAiB,MAAM,SAAS,OAAO,GAAG,CAAC,EAAE;AAAA,IACzE;AAAA,IAEA,KAAK,wBAAwB;AACzB,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,MAAM,UAAmB,MAAM,QAAQ,OAAO,GAAG,CAAC,EAAE;AAAA,IAC1E;AAAA,IAEA,KAAK,sBAAsB;AACvB,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,MAAM,QAAiB,MAAM,WAAW,OAAO,GAAG,CAAC,GAAG,YAAY,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IACrH;AAAA,IAEA,KAAK,sBAAsB;AACvB,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,YAAM,SAAS,OAAO,GAAG,CAAC;AAC1B,YAAM,cAAc,OAAO,GAAG,CAAC;AAC/B,YAAM,YAAY,OAAO,GAAG,CAAC,MAAM;AACnC,YAAM,WAAW,OAAO,GAAG,CAAC;AAC5B,YAAM,UAAU,OAAO,GAAG,EAAE;AAE5B,UAAI,WAAW,IAAI,eAAe;AAClC,YAAM,cAAc,SAAS,GAAG,EAAE;AAClC,UAAI,aAAa;AACb,cAAM,KAAK,YAAY,WAAW;AAClC,mBAAW,OAAO,IAAI,CAAC;AACvB,uBAAe,OAAO,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC;AAAA,MAChD;AACA,UAAI,CAAC,UAAU;AACX,cAAM,WAAW,SAAS,GAAG,CAAC;AAC9B,YAAI,UAAU;AACV,gBAAM,MAAM,YAAY,QAAQ;AAChC,cAAI,CAAC,SAAU,YAAW,OAAO,KAAK,CAAC;AACvC,cAAI,CAAC,aAAc,gBAAe,OAAO,KAAK,CAAC;AAAA,QACnD;AAAA,MACJ;AAEA,aAAO;AAAA,QACH,GAAG;AAAA,QAAM,MAAM;AAAA,QAAiB;AAAA,QAAM;AAAA,QAAQ;AAAA,QAAU;AAAA,QACxD;AAAA,QAAa;AAAA,QAAW,OAAO,cAAc,KAAK,CAAC;AAAA,QACnD;AAAA,QAAU;AAAA,MACd;AAAA,IACJ;AAAA,IAEA,KAAK,wBAAwB;AACzB,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,YAAM,YAAY,OAAO,GAAG,CAAC;AAC7B,YAAM,YAAoC,EAAE,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO;AAC/E,aAAO,EAAE,GAAG,MAAM,MAAM,UAAmB,MAAM,QAAQ,UAAU,SAAS,KAAK,UAAU,SAAS,GAAG;AAAA,IAC3G;AAAA,IAEA,KAAK;AACD,aAAO;AAAA,QACH,GAAG;AAAA,QAAM,MAAM;AAAA,QACf,cAAc,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC;AAAA,QACzC,aAAa,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC;AAAA,MAC5C;AAAA,IAEJ,KAAK,wBAAwB;AACzB,YAAM,WAAW,OAAO,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AACpD,YAAM,SAAS,OAAO,GAAG,CAAC;AAC1B,YAAM,iBAAiB,OAAO,GAAG,CAAC;AAClC,YAAM,QAAsB,CAAC;AAC7B,YAAM,WAAW,YAAY,GAAG,CAAC;AACjC,iBAAW,MAAM,UAAU;AACvB,YAAI;AAAE,gBAAM,KAAK,gBAAgB,EAAE,CAAC;AAAA,QAAG,QAAQ;AAAA,QAAE;AAAA,MACrD;AACA,aAAO,EAAE,GAAG,MAAM,MAAM,UAAmB,UAAU,QAAQ,gBAAgB,MAAM;AAAA,IACvF;AAAA,IAEA,KAAK,wBAAwB;AACzB,YAAM,WAAW,OAAO,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AACpD,YAAM,QAAsB,CAAC;AAC7B,YAAM,WAAW,YAAY,GAAG,CAAC;AACjC,iBAAW,MAAM,UAAU;AACvB,YAAI;AAAE,gBAAM,KAAK,gBAAgB,EAAE,CAAC;AAAA,QAAG,QAAQ;AAAA,QAAE;AAAA,MACrD;AACA,aAAO,EAAE,GAAG,MAAM,MAAM,gBAAyB,UAAU,MAAM;AAAA,IACrE;AAAA,IAEA,KAAK,2BAA2B;AAC5B,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,MAAM,aAAsB,MAAM,UAAU,OAAO,GAAG,CAAC,EAAE;AAAA,IAC/E;AAAA,IAEA,KAAK,2BAA2B;AAC5B,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,UAAI,UAAU,IAAI,WAAW;AAC7B,YAAM,WAAW,SAAS,GAAG,CAAC;AAC9B,UAAI,UAAU;AACV,cAAM,KAAK,YAAY,QAAQ;AAC/B,kBAAU,OAAO,IAAI,CAAC;AACtB,cAAM,WAAW,SAAS,IAAI,CAAC;AAC/B,YAAI,UAAU;AACV,gBAAM,YAAY,YAAY,QAAQ;AACtC,qBAAW,OAAO,WAAW,CAAC;AAAA,QAClC;AAAA,MACJ;AACA,aAAO,EAAE,GAAG,MAAM,MAAM,aAAsB,MAAM,SAAS,SAAS;AAAA,IAC1E;AAAA,IAEA,KAAK,0BAA0B;AAC3B,YAAM,aAAa,OAAO,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC;AACtD,aAAO,EAAE,GAAG,MAAM,MAAM,YAAqB,YAAY,cAAc,OAAO,GAAG,CAAC,EAAE;AAAA,IACxF;AAAA,IAEA,KAAK,6BAA6B;AAC9B,YAAM,UAAU,SAAS,GAAG,CAAC;AAC7B,YAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,aAAO,EAAE,GAAG,MAAM,MAAM,YAAqB,MAAM,cAAc,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAClG;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,4BAA4B;AAC7B,YAAM,WAAW,OAAO,GAAG,CAAC,KAAK,QAAQ,OAAO,GAAG,CAAC,CAAC;AACrD,YAAM,WAAqE,CAAC;AAC5E,YAAM,WAAW,YAAY,GAAG,CAAC;AACjC,iBAAW,MAAM,UAAU;AACvB,YAAI;AACA,gBAAM,KAAK,YAAY,EAAE;AACzB,gBAAM,UAAU,SAAS,IAAI,CAAC;AAC9B,gBAAM,OAAO,OAAO,IAAI,CAAC;AACzB,gBAAM,QAAQ,OAAO,IAAI,CAAC;AAC1B,gBAAM,OAAO,UAAU,UAAU,OAAO,IAAI,EAAE,IAAI,KAAK,UAAU,IAAI,UAAU,GAAG;AAClF,mBAAS,KAAK,EAAE,MAAM,MAAM,MAAM,CAAC;AAAA,QACvC,QAAQ;AAAA,QAAE;AAAA,MACd;AACA,aAAO,EAAE,GAAG,MAAM,MAAM,cAAuB,UAAU,SAAS;AAAA,IACtE;AAAA,IAEA,KAAK;AACD,aAAO,EAAE,GAAG,MAAM,MAAM,WAAoB,QAAQ,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAErF,KAAK;AAAA,IACL,KAAK;AACD,aAAO,EAAE,GAAG,MAAM,MAAM,QAAiB,QAAQ,OAAO,GAAG,CAAC,EAAE;AAAA,IAElE,KAAK,2BAA2B;AAC5B,YAAM,SAAS,OAAO,OAAO,GAAG,CAAC,CAAC;AAClC,aAAO,EAAE,GAAG,MAAM,MAAM,aAAsB,QAAQ,OAAO,OAAO,GAAG,CAAC,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,IAC9F;AAAA,IAEA,KAAK;AAAA,IACL,KAAK,mCAAmC;AACpC,YAAM,SAAS,OAAO,GAAG,CAAC,KAAK,UAAU,OAAO,GAAG,CAAC,CAAC;AACrD,YAAM,QAAsB,CAAC;AAC7B,YAAM,WAAW,YAAY,GAAG,CAAC;AACjC,iBAAW,MAAM,UAAU;AACvB,YAAI;AAAE,gBAAM,KAAK,UAAU,EAAE,CAAC;AAAA,QAAG,QAAQ;AAAA,QAAE;AAAA,MAC/C;AACA,aAAO,EAAE,GAAG,MAAM,MAAM,WAAoB,QAAQ,MAAM;AAAA,IAC9D;AAAA,IAEA;AACI,aAAO,EAAE,GAAG,MAAM,MAAM,WAAoB,OAAO;AAAA,EAC3D;AACJ;AAEO,SAAS,qBAAqB,SAA8B;AAC/D,QAAM,SAAsB,CAAC;AAC7B,QAAM,aAAa,YAAY,OAAO;AAEtC,aAAW,MAAM,WAAW,OAAO,OAAK,EAAE,OAAO,KAAK,EAAE,OAAO,CAAC,GAAG;AAC/D,UAAM,SAAS,GAAG;AAClB,UAAM,YAAY,YAAY,MAAM;AACpC,UAAM,SAAS,OAAO,WAAW,CAAC;AAClC,UAAM,eAAe,SAAS,WAAW,CAAC;AAC1C,QAAI,CAAC,UAAU,CAAC,aAAc;AAE9B,QAAI;AACA,aAAO,KAAK,oBAAoB,QAAQ,YAAY,CAAC;AAAA,IACzD,QAAQ;AAAA,IAAE;AAAA,EACd;AAEA,SAAO;AACX;;;AD1VA,IAAM,aAAa;AACnB,IAAM,sBAAsB;AAE5B,SAAS,QAAQ,KAAa,SAI3B;AACC,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACpC,UAAM,MAAM,IAAI,WAAW,OAAO,IAAI,QAAQ;AAC9C,UAAM,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,GAAG,CAAC,QAAQ;AAC3C,YAAM,SAAmB,CAAC;AAC1B,YAAM,MAAM,IAAI,QAAQ,kBAAkB;AAC1C,YAAM,SAAU,QAAQ,UAAU,QAAQ,OACpC,IAAI,KAAK,QAAQ,OAAY,4BAAuB,IAAS,kBAAa,CAAC,IAC3E;AACN,aAAO,GAAG,QAAQ,CAAC,MAAc,OAAO,KAAK,CAAC,CAAC;AAC/C,aAAO,GAAG,OAAO,MAAM,QAAQ;AAAA,QAC3B,QAAQ,IAAI,cAAc;AAAA,QAC1B,SAAS,IAAI;AAAA,QACb,MAAM,OAAO,OAAO,MAAM;AAAA,MAC9B,CAAC,CAAC;AACF,aAAO,GAAG,SAAS,MAAM;AAAA,IAC7B,CAAC;AACD,QAAI,GAAG,SAAS,MAAM;AACtB,QAAI,WAAW,MAAQ,MAAM;AAAE,UAAI,QAAQ;AAAG,aAAO,IAAI,MAAM,iBAAiB,CAAC;AAAA,IAAG,CAAC;AAAA,EACzF,CAAC;AACL;AAEA,SAAS,UAAU,eAA+B;AAC9C,MAAI,CAAC,cAAe,QAAO;AAC3B,QAAM,IAAI,cAAc,YAAY;AACpC,MAAI,EAAE,WAAW,IAAI,KAAK,EAAE,SAAS,IAAI,EAAG,QAAO;AACnD,MAAI,EAAE,WAAW,IAAI,KAAK,EAAE,SAAS,IAAI,EAAG,QAAO;AACnD,SAAO;AACX;AAEO,IAAM,aAAN,cAAyB,aAAa;AAAA,EACjC,KAAuB;AAAA,EACvB,iBAAwD;AAAA,EACxD,oBAAoB;AAAA,EACpB,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EAED;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAA4B;AACpC,UAAM;AACN,SAAK,WAAW,QAAQ,SAAS,QAAQ,MAAM,EAAE;AACjD,SAAK,iBAAiB,QAAQ,iBAAiB,qBAAqB,QAAQ,OAAO,EAAE;AACrF,QAAI,CAAC,QAAQ,OAAQ,OAAM,IAAI,MAAM,yDAAyD;AAC9F,SAAK,SAAS,QAAQ;AACtB,SAAK,gBAAgB,QAAQ,iBAAiB;AAC9C,SAAK,uBAAuB,QAAQ,wBAAwB;AAC5D,SAAK,oBAAoB,QAAQ,qBAAqB;AACtD,SAAK,QAAQ,QAAQ,SAAS;AAAA,EAClC;AAAA,EAEA,MAAM,UAAyB;AAC3B,SAAK,mBAAmB;AAExB,UAAM,OAAO,MAAM,QAAQ,2BAA2B,KAAK,QAAQ,SAAS;AAAA,MACxE,cAAc;AAAA,MACd,UAAU;AAAA,MACV,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,IACvB,CAAC;AAED,QAAI,QAAQ;AACZ,eAAW,MAAM,CAAC,KAAK,QAAQ,YAAY,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG;AACxD,UAAI,OAAO,OAAO,YAAY,GAAG,WAAW,QAAQ,GAAG;AACnD,gBAAQ,GAAG,MAAM,GAAG,EAAE,CAAC,EAAE,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG;AACrD;AAAA,MACJ;AAAA,IACJ;AACA,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iCAAiC;AAE7D,UAAM,OAAO,KAAK,KAAK,SAAS;AAChC,QAAI,SAAS;AACb,UAAM,YAAY,KAAK,MAAM,8BAA8B;AAC3D,QAAI,WAAW;AACX,UAAI;AACA,cAAM,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC;AACpC,cAAM,UAAU,KAAK,UAAU,IAAI;AACnC,cAAM,IAAI,QAAQ,MAAM,wBAAwB;AAChD,YAAI,EAAG,UAAS,EAAE,CAAC;AAAA,MACvB,QAAQ;AAAA,MAAE;AAAA,IACd;AACA,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,SAAS,KAAK,QAAQ,wBAAwB;AAC3E,SAAK,UAAU;AAEf,UAAM,UAAU,KAAK,MAAM,iCAAiC;AAC5D,UAAM,gBAAgB,UAAU,QAAQ,CAAC,IAAI;AAC7C,UAAM,SAAS,UAAU,aAAa;AAEtC,UAAM,WAAW,IAAI,gBAAgB;AAAA,MACjC,cAAc;AAAA,MAAU,iBAAiB;AAAA,MAAO,gBAAgB;AAAA,MAChE,cAAc;AAAA,MAAQ,eAAe;AAAA,MAAQ,kBAAkB;AAAA,MAC/D,kBAAkB;AAAA,MAAS,cAAc;AAAA,MACzC,iBAAiB,WAAW,MAAM,UAAU,EAAE,CAAC,KAAK;AAAA,MACpD,gBAAgB;AAAA,MAAQ,SAAS,KAAK,eAAe,EAAE,gBAAgB,EAAE;AAAA,MACzE,UAAU;AAAA,MAAc,eAAe;AAAA,MAAK,qBAAqB;AAAA,MACjE,UAAU;AAAA,MAAQ,kBAAkB;AAAA,MAAM,WAAW;AAAA,MAAK,KAAK;AAAA,MAC/D,SAAS;AAAA,MAAM,cAAc;AAAA,MAAM,cAAc;AAAA,MAAK,SAAS;AAAA,MAC/D,UAAU;AAAA,MAAY,uBAAuB;AAAA,MAAK,UAAU;AAAA,MAC5D,oBAAoB;AAAA,MAAS,mBAAmB;AAAA,MAAY,UAAU;AAAA,IAC1E,CAAC;AAED,UAAM,WAAW,WAAW,MAAM,6CAA6C,QAAQ;AAEvF,UAAM,UAAU,GAAG,KAAK,aAAa;AAErC,QAAI;AACJ,QAAI;AACA,YAAM,WAAW,MAAM,MAAM,SAAS;AAAA,QAClC,QAAQ;AAAA,QACR,SAAS;AAAA,UACL,gBAAgB;AAAA,UAChB,aAAa,KAAK;AAAA,QACtB;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,KAAK,SAAS,CAAC;AAAA,MAC1C,CAAC;AACD,YAAM,WAAW,MAAM,SAAS,KAAK;AAErC,UAAI,SAAS,gBAAgB,KAAK,SAAS,MAAM,YAAY;AACzD,gBAAS,SAAS,KAAK,WAAsB,QAAQ,eAAe,QAAQ;AAAA,MAChF,OAAO;AACH,gBAAQ,SAAS,QAAQ,eAAe,QAAQ;AAAA,MACpD;AAAA,IACJ,QAAQ;AACJ,cAAQ,SAAS,QAAQ,eAAe,QAAQ;AAAA,IACpD;AAEA,WAAO,IAAI,QAAc,CAAC,SAAS,WAAW;AAC1C,WAAK,KAAK,IAAI,UAAU,OAAO;AAAA,QAC3B,SAAS;AAAA,UACL,cAAc;AAAA,UACd,UAAU,SAAS,KAAK;AAAA,UACxB,UAAU;AAAA,QACd;AAAA,MACJ,CAAC;AAED,WAAK,GAAG,GAAG,QAAQ,MAAM;AACrB,aAAK,aAAa;AAClB,aAAK,oBAAoB;AAEzB,aAAK,GAAI,KAAK,eAAe,MAAM,CAAC;AACpC,aAAK,GAAI,KAAK,iBAAiB,MAAM,CAAC;AACtC,aAAK,eAAe,MAAM;AAE1B,cAAM,WAAqB;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,UACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACxC;AAEA,aAAK,KAAK,WAAW;AACrB,aAAK,KAAK,YAAY,QAAQ;AAC9B,gBAAQ;AAAA,MACZ,CAAC;AAED,WAAK,GAAG,GAAG,WAAW,CAAC,YAAoB;AACvC,aAAK,YAAY,OAAO,KAAK,OAAO,CAAC;AAAA,MACzC,CAAC;AAED,WAAK,GAAG,GAAG,SAAS,CAAC,MAAM,WAAW;AAClC,aAAK,aAAa;AAClB,aAAK,cAAc;AAEnB,cAAM,YAAY,QAAQ,SAAS,KAAK;AACxC,aAAK,KAAK,gBAAgB,MAAM,SAAS;AAEzC,YAAI,CAAC,KAAK,oBAAoB,KAAK,iBAAiB,KAAK,oBAAoB,KAAK,sBAAsB;AACpG,eAAK;AACL,gBAAM,QAAQ,KAAK,IAAI,MAAO,KAAK,IAAI,GAAG,KAAK,oBAAoB,CAAC,GAAG,GAAM;AAC7E,qBAAW,MAAM,KAAK,QAAQ,EAAE,MAAM,OAAK,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG,KAAK;AAAA,QAC5E;AAAA,MACJ,CAAC;AAED,WAAK,GAAG,GAAG,SAAS,CAAC,QAAQ;AACzB,aAAK,KAAK,SAAS,GAAG;AACtB,YAAI,CAAC,KAAK,WAAY,QAAO,GAAG;AAAA,MACpC,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AAAA,EAEA,aAAmB;AACf,SAAK,mBAAmB;AACxB,SAAK,cAAc;AACnB,QAAI,KAAK,IAAI;AACT,WAAK,GAAG,MAAM,GAAI;AAClB,WAAK,KAAK;AAAA,IACd;AACA,SAAK,aAAa;AAAA,EACtB;AAAA,EAEA,IAAI,YAAqB;AACrB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,IAAI,aAAqB;AACrB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,IAAI,SAAiB;AACjB,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,GAAqC,OAAU,UAAqC;AAChF,WAAO,MAAM,GAAG,OAAO,QAAoC;AAAA,EAC/D;AAAA,EAEA,KAAuC,OAAU,UAAqC;AAClF,WAAO,MAAM,KAAK,OAAO,QAAoC;AAAA,EACjE;AAAA,EAEA,IAAsC,OAAU,UAAqC;AACjF,WAAO,MAAM,IAAI,OAAO,QAAoC;AAAA,EAChE;AAAA,EAEA,KAAuC,UAAa,MAAgD;AAChG,WAAO,MAAM,KAAK,OAAO,GAAG,IAAI;AAAA,EACpC;AAAA,EAEQ,YAAY,KAAmB;AACnC,QAAI;AACA,YAAM,SAAS,YAAY,GAAG;AAC9B,YAAM,UAAU,OAAO,KAAK,OAAK,EAAE,OAAO,KAAK,EAAE,OAAO,CAAC;AACzD,YAAM,KAAK,UAAU,QAAQ,QAAkB;AAC/C,YAAM,OAAO,OAAO,QAAQ,CAAC;AAC7B,YAAM,SAAS,SAAS,QAAQ,CAAC;AAEjC,UAAI,KAAK,MAAM,KAAK,IAAI,eAAe,UAAU,MAAM;AACnD,aAAK,GAAG,KAAK,SAAS,EAAE,CAAC;AAAA,MAC7B;AAEA,UAAI,SAAS,SAAS,UAAU,OAAO,SAAS,GAAG;AAC/C,YAAI,QAAQ;AACZ,YAAI,MAAM,SAAS,KAAK,MAAM,CAAC,MAAM,MAAQ,MAAM,CAAC,MAAM,KAAM;AAC5D,cAAI;AAAE,oBAAa,gBAAW,KAAK;AAAA,UAAG,QAAQ;AAAA,UAAE;AAAA,QACpD;AAEA,cAAM,SAAS,qBAAqB,KAAK;AACzC,mBAAW,OAAO,QAAQ;AACtB,eAAK;AACL,eAAK,KAAK,SAAS,GAAG;AACtB,eAAK,KAAK,IAAI,MAAgC,GAAU;AAAA,QAC5D;AAAA,MACJ;AAAA,IACJ,QAAQ;AAAA,IAAE;AAAA,EACd;AAAA,EAEQ,eAAe,QAAsB;AACzC,SAAK,cAAc;AACnB,SAAK,iBAAiB,YAAY,MAAM;AACpC,UAAI,KAAK,IAAI,eAAe,UAAU,MAAM;AACxC,aAAK,GAAG,KAAK,eAAe,MAAM,CAAC;AAAA,MACvC;AAAA,IACJ,GAAG,KAAK,iBAAiB;AAAA,EAC7B;AAAA,EAEQ,gBAAsB;AAC1B,QAAI,KAAK,gBAAgB;AACrB,oBAAc,KAAK,cAAc;AACjC,WAAK,iBAAiB;AAAA,IAC1B;AAAA,EACJ;AACJ;","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/proto.ts"],"sourcesContent":["import { EventEmitter } from 'events';\r\nimport * as http from 'http';\r\nimport * as https from 'https';\r\nimport * as zlib from 'zlib';\r\nimport WebSocket from 'ws';\r\nimport type { TikTokLiveOptions, TikTokLiveEvents, RoomInfo, LiveEvent } from './types.js';\r\nimport {\r\n decodeProto,\r\n getStr,\r\n getBytes,\r\n buildHeartbeat,\r\n buildImEnterRoom,\r\n buildAck,\r\n parseWebcastResponse,\r\n} from './proto.js';\r\n\r\nconst DEFAULT_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36';\r\nconst DEFAULT_SIGN_SERVER = 'https://api.tik.tools';\r\n\r\nfunction httpGet(url: string, headers: Record<string, string>): Promise<{\r\n status: number;\r\n headers: http.IncomingHttpHeaders;\r\n body: Buffer;\r\n}> {\r\n return new Promise((resolve, reject) => {\r\n const mod = url.startsWith('https') ? https : http;\r\n const req = mod.get(url, { headers }, (res) => {\r\n const chunks: Buffer[] = [];\r\n const enc = res.headers['content-encoding'];\r\n const stream = (enc === 'gzip' || enc === 'br')\r\n ? res.pipe(enc === 'br' ? zlib.createBrotliDecompress() : zlib.createGunzip())\r\n : res;\r\n stream.on('data', (c: Buffer) => chunks.push(c));\r\n stream.on('end', () => resolve({\r\n status: res.statusCode || 0,\r\n headers: res.headers,\r\n body: Buffer.concat(chunks),\r\n }));\r\n stream.on('error', reject);\r\n });\r\n req.on('error', reject);\r\n req.setTimeout(15_000, () => { req.destroy(); reject(new Error('Request timeout')); });\r\n });\r\n}\r\n\r\nfunction getWsHost(clusterRegion: string): string {\r\n if (!clusterRegion) return 'webcast-ws.tiktok.com';\r\n const r = clusterRegion.toLowerCase();\r\n if (r.startsWith('eu') || r.includes('eu')) return 'webcast-ws.eu.tiktok.com';\r\n if (r.startsWith('us') || r.includes('us')) return 'webcast-ws.us.tiktok.com';\r\n return 'webcast-ws.tiktok.com';\r\n}\r\n\r\nexport class TikTokLive extends EventEmitter {\r\n private ws: WebSocket | null = null;\r\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\r\n private reconnectAttempts = 0;\r\n private intentionalClose = false;\r\n private _connected = false;\r\n private _eventCount = 0;\r\n private _roomId = '';\r\n\r\n private readonly uniqueId: string;\r\n private readonly signServerUrl: string;\r\n private readonly apiKey: string;\r\n private readonly autoReconnect: boolean;\r\n private readonly maxReconnectAttempts: number;\r\n private readonly heartbeatInterval: number;\r\n private readonly debug: boolean;\r\n\r\n constructor(options: TikTokLiveOptions) {\r\n super();\r\n this.uniqueId = options.uniqueId.replace(/^@/, '');\r\n this.signServerUrl = (options.signServerUrl || DEFAULT_SIGN_SERVER).replace(/\\/$/, '');\r\n if (!options.apiKey) throw new Error('apiKey is required. Get a free key at https://tik.tools');\r\n this.apiKey = options.apiKey;\r\n this.autoReconnect = options.autoReconnect ?? true;\r\n this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;\r\n this.heartbeatInterval = options.heartbeatInterval ?? 10_000;\r\n this.debug = options.debug ?? false;\r\n }\r\n\r\n async connect(): Promise<void> {\r\n this.intentionalClose = false;\r\n\r\n const resp = await httpGet(`https://www.tiktok.com/@${this.uniqueId}/live`, {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',\r\n 'Accept-Encoding': 'gzip, deflate, br',\r\n 'Accept-Language': 'en-US,en;q=0.9',\r\n });\r\n\r\n let ttwid = '';\r\n for (const sc of [resp.headers['set-cookie'] || []].flat()) {\r\n if (typeof sc === 'string' && sc.startsWith('ttwid=')) {\r\n ttwid = sc.split(';')[0].split('=').slice(1).join('=');\r\n break;\r\n }\r\n }\r\n if (!ttwid) throw new Error('Failed to obtain session cookie');\r\n\r\n const html = resp.body.toString();\r\n let roomId = '';\r\n const sigiMatch = html.match(/id=\"SIGI_STATE\"[^>]*>([^<]+)/);\r\n if (sigiMatch) {\r\n try {\r\n const json = JSON.parse(sigiMatch[1]);\r\n const jsonStr = JSON.stringify(json);\r\n const m = jsonStr.match(/\"roomId\"\\s*:\\s*\"(\\d+)\"/);\r\n if (m) roomId = m[1];\r\n } catch { }\r\n }\r\n if (!roomId) throw new Error(`User @${this.uniqueId} is not currently live`);\r\n this._roomId = roomId;\r\n\r\n const crMatch = html.match(/\"clusterRegion\"\\s*:\\s*\"([^\"]+)\"/);\r\n const clusterRegion = crMatch ? crMatch[1] : '';\r\n const wsHost = getWsHost(clusterRegion);\r\n\r\n const wsParams = new URLSearchParams({\r\n version_code: '270000', device_platform: 'web', cookie_enabled: 'true',\r\n screen_width: '1920', screen_height: '1080', browser_language: 'en-US',\r\n browser_platform: 'Win32', browser_name: 'Mozilla',\r\n browser_version: DEFAULT_UA.split('Mozilla/')[1] || '5.0',\r\n browser_online: 'true', tz_name: Intl.DateTimeFormat().resolvedOptions().timeZone,\r\n app_name: 'tiktok_web', sup_ws_ds_opt: '1', update_version_code: '2.0.0',\r\n compress: 'gzip', webcast_language: 'en', ws_direct: '1', aid: '1988',\r\n live_id: '12', app_language: 'en', client_enter: '1', room_id: roomId,\r\n identity: 'audience', history_comment_count: '6', last_rtt: '0',\r\n heartbeat_duration: '10000', resp_content_type: 'protobuf', did_rule: '3',\r\n });\r\n\r\n const rawWsUrl = `https://${wsHost}/webcast/im/ws_proxy/ws_reuse_supplement/?${wsParams}`;\r\n\r\n const signUrl = `${this.signServerUrl}/webcast/sign_url`;\r\n\r\n let wsUrl: string;\r\n try {\r\n const signResp = await fetch(signUrl, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'x-api-key': this.apiKey,\r\n },\r\n body: JSON.stringify({ url: rawWsUrl }),\r\n });\r\n const signData = await signResp.json() as Record<string, any>;\r\n\r\n if (signData.status_code === 0 && signData.data?.signed_url) {\r\n wsUrl = (signData.data.signed_url as string).replace(/^https:\\/\\//, 'wss://');\r\n } else {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n } catch {\r\n wsUrl = rawWsUrl.replace(/^https:\\/\\//, 'wss://');\r\n }\r\n\r\n return new Promise<void>((resolve, reject) => {\r\n this.ws = new WebSocket(wsUrl, {\r\n headers: {\r\n 'User-Agent': DEFAULT_UA,\r\n 'Cookie': `ttwid=${ttwid}`,\r\n 'Origin': 'https://www.tiktok.com',\r\n },\r\n });\r\n\r\n this.ws.on('open', () => {\r\n this._connected = true;\r\n this.reconnectAttempts = 0;\r\n\r\n this.ws!.send(buildHeartbeat(roomId));\r\n this.ws!.send(buildImEnterRoom(roomId));\r\n this.startHeartbeat(roomId);\r\n\r\n const roomInfo: RoomInfo = {\r\n roomId,\r\n wsHost,\r\n clusterRegion,\r\n connectedAt: new Date().toISOString(),\r\n };\r\n\r\n this.emit('connected');\r\n this.emit('roomInfo', roomInfo);\r\n resolve();\r\n });\r\n\r\n this.ws.on('message', (rawData: Buffer) => {\r\n this.handleFrame(Buffer.from(rawData));\r\n });\r\n\r\n this.ws.on('close', (code, reason) => {\r\n this._connected = false;\r\n this.stopHeartbeat();\r\n\r\n const reasonStr = reason?.toString() || '';\r\n this.emit('disconnected', code, reasonStr);\r\n\r\n if (!this.intentionalClose && this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {\r\n this.reconnectAttempts++;\r\n const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts - 1), 30_000);\r\n setTimeout(() => this.connect().catch(e => this.emit('error', e)), delay);\r\n }\r\n });\r\n\r\n this.ws.on('error', (err) => {\r\n this.emit('error', err);\r\n if (!this._connected) reject(err);\r\n });\r\n });\r\n }\r\n\r\n disconnect(): void {\r\n this.intentionalClose = true;\r\n this.stopHeartbeat();\r\n if (this.ws) {\r\n this.ws.close(1000);\r\n this.ws = null;\r\n }\r\n this._connected = false;\r\n }\r\n\r\n get connected(): boolean {\r\n return this._connected;\r\n }\r\n\r\n get eventCount(): number {\r\n return this._eventCount;\r\n }\r\n\r\n get roomId(): string {\r\n return this._roomId;\r\n }\r\n\r\n on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.on(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.once(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this {\r\n return super.off(event, listener as (...args: any[]) => void);\r\n }\r\n\r\n emit<K extends keyof TikTokLiveEvents>(event: K, ...args: Parameters<TikTokLiveEvents[K]>): boolean {\r\n return super.emit(event, ...args);\r\n }\r\n\r\n private handleFrame(buf: Buffer): void {\r\n try {\r\n const fields = decodeProto(buf);\r\n const idField = fields.find(f => f.fn === 2 && f.wt === 0);\r\n const id = idField ? idField.value as bigint : 0n;\r\n const type = getStr(fields, 7);\r\n const binary = getBytes(fields, 8);\r\n\r\n if (id > 0n && this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildAck(id));\r\n }\r\n\r\n if (type === 'msg' && binary && binary.length > 0) {\r\n let inner = binary;\r\n if (inner.length > 2 && inner[0] === 0x1f && inner[1] === 0x8b) {\r\n try { inner = zlib.gunzipSync(inner); } catch { }\r\n }\r\n\r\n const events = parseWebcastResponse(inner);\r\n for (const evt of events) {\r\n this._eventCount++;\r\n this.emit('event', evt);\r\n this.emit(evt.type as keyof TikTokLiveEvents, evt as any);\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n private startHeartbeat(roomId: string): void {\r\n this.stopHeartbeat();\r\n this.heartbeatTimer = setInterval(() => {\r\n if (this.ws?.readyState === WebSocket.OPEN) {\r\n this.ws.send(buildHeartbeat(roomId));\r\n }\r\n }, this.heartbeatInterval);\r\n }\r\n\r\n private stopHeartbeat(): void {\r\n if (this.heartbeatTimer) {\r\n clearInterval(this.heartbeatTimer);\r\n this.heartbeatTimer = null;\r\n }\r\n }\r\n}\r\n","import type { LiveEvent, TikTokUser, BattleTeam, BattleTeamUser } from './types.js';\r\n\r\nexport function decodeVarint(buf: Buffer, offset: number): { value: number; offset: number } {\r\n let result = 0, shift = 0;\r\n while (offset < buf.length) {\r\n const byte = buf[offset++];\r\n result |= (byte & 0x7F) << shift;\r\n if ((byte & 0x80) === 0) break;\r\n shift += 7;\r\n }\r\n return { value: result >>> 0, offset };\r\n}\r\n\r\nexport function decodeVarint64(buf: Buffer, offset: number): { value: bigint; offset: number } {\r\n let result = 0n, shift = 0n;\r\n while (offset < buf.length) {\r\n const byte = BigInt(buf[offset++]);\r\n result |= (byte & 0x7Fn) << shift;\r\n if ((byte & 0x80n) === 0n) break;\r\n shift += 7n;\r\n }\r\n return { value: result, offset };\r\n}\r\n\r\nexport function encodeVarint(v: number | bigint): Buffer {\r\n const bytes: number[] = [];\r\n let n = typeof v === 'bigint' ? v : BigInt(v);\r\n do {\r\n let b = Number(n & 0x7Fn);\r\n n >>= 7n;\r\n if (n > 0n) b |= 0x80;\r\n bytes.push(b);\r\n } while (n > 0n);\r\n return Buffer.from(bytes);\r\n}\r\n\r\nexport interface ProtoField {\r\n fn: number;\r\n wt: number;\r\n value: Buffer | number | bigint;\r\n}\r\n\r\nexport function encodeField(fn: number, wt: number, value: Buffer | bigint | number | string): Buffer {\r\n const tag = encodeVarint((fn << 3) | wt);\r\n if (wt === 0) {\r\n return Buffer.concat([tag, encodeVarint(typeof value === 'number' ? BigInt(value) : value as bigint)]);\r\n }\r\n const data = typeof value === 'string' ? Buffer.from(value) : value as Buffer;\r\n return Buffer.concat([tag, encodeVarint(data.length), data]);\r\n}\r\n\r\nexport function decodeProto(buf: Buffer): ProtoField[] {\r\n const fields: ProtoField[] = [];\r\n let offset = 0;\r\n while (offset < buf.length) {\r\n const tagResult = decodeVarint(buf, offset);\r\n offset = tagResult.offset;\r\n const fn = tagResult.value >> 3;\r\n const wt = tagResult.value & 7;\r\n if (wt === 0) {\r\n const r = decodeVarint64(buf, offset);\r\n offset = r.offset;\r\n fields.push({ fn, wt, value: r.value });\r\n } else if (wt === 2) {\r\n const lenR = decodeVarint(buf, offset);\r\n offset = lenR.offset;\r\n const data = buf.subarray(offset, offset + lenR.value);\r\n offset += lenR.value;\r\n fields.push({ fn, wt, value: data });\r\n } else if (wt === 1) {\r\n fields.push({ fn, wt, value: buf.readBigInt64LE(offset) });\r\n offset += 8;\r\n } else if (wt === 5) {\r\n fields.push({ fn, wt, value: BigInt(buf.readInt32LE(offset)) });\r\n offset += 4;\r\n } else {\r\n break;\r\n }\r\n }\r\n return fields;\r\n}\r\n\r\nexport function getStr(fields: ProtoField[], fn: number): string {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? (f.value as Buffer).toString('utf-8') : '';\r\n}\r\n\r\nexport function getBytes(fields: ProtoField[], fn: number): Buffer | null {\r\n const f = fields.find(x => x.fn === fn && x.wt === 2);\r\n return f ? f.value as Buffer : null;\r\n}\r\n\r\nexport function getInt(fields: ProtoField[], fn: number): number {\r\n const f = fields.find(x => x.fn === fn && x.wt === 0);\r\n return f ? Number(f.value) : 0;\r\n}\r\n\r\nexport function getAllBytes(fields: ProtoField[], fn: number): Buffer[] {\r\n return fields.filter(x => x.fn === fn && x.wt === 2).map(x => x.value as Buffer);\r\n}\r\n\r\nexport function buildHeartbeat(roomId: string): Buffer {\r\n const payload = encodeField(1, 0, BigInt(roomId));\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'hb'),\r\n encodeField(8, 2, payload),\r\n ]);\r\n}\r\n\r\nexport function buildImEnterRoom(roomId: string): Buffer {\r\n const inner = Buffer.concat([\r\n encodeField(1, 0, BigInt(roomId)),\r\n encodeField(4, 0, 12n),\r\n encodeField(5, 2, 'audience'),\r\n encodeField(6, 2, ''),\r\n encodeField(9, 2, ''),\r\n encodeField(10, 2, ''),\r\n ]);\r\n return Buffer.concat([\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'im_enter_room'),\r\n encodeField(8, 2, inner),\r\n ]);\r\n}\r\n\r\nexport function buildAck(id: bigint): Buffer {\r\n return Buffer.concat([\r\n encodeField(2, 0, id),\r\n encodeField(6, 2, 'pb'),\r\n encodeField(7, 2, 'ack'),\r\n ]);\r\n}\r\n\r\n// ── User parsing ────────────────────────────────────────────────────\r\n// Proto: User { userId=1, nickname=3, profilePicture=9, extraAttributes=22, badge=64, uniqueId=38 }\r\n// Proto: LinkUser { userId=1, nickname=2, profilePicture=3, uniqueId=4 }\r\n// Proto: ProfilePicture { repeated urls=1 }\r\n\r\nfunction parseUser(data: Buffer): TikTokUser {\r\n const f = decodeProto(data);\r\n const id = String(getInt(f, 1) || getStr(f, 1));\r\n const nickname = getStr(f, 3) || getStr(f, 2);\r\n const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2) || '';\r\n\r\n let profilePicture: string | undefined;\r\n const avatarBuf = getBytes(f, 9) || getBytes(f, 3);\r\n if (avatarBuf) {\r\n try {\r\n const avatarFields = decodeProto(avatarBuf);\r\n // ProfilePicture.urls is repeated string at field 1\r\n const urlBufs = getAllBytes(avatarFields, 1);\r\n if (urlBufs.length > 0) profilePicture = urlBufs[0].toString('utf-8');\r\n } catch { }\r\n }\r\n\r\n // Badges from field 64 → field 21 (repeated UserBadge)\r\n const badges: string[] = [];\r\n const badgeBuf = getBytes(f, 64);\r\n if (badgeBuf) {\r\n try {\r\n const badgeFields = decodeProto(badgeBuf);\r\n const badgeItems = getAllBytes(badgeFields, 21);\r\n for (const bi of badgeItems) {\r\n const bf = decodeProto(bi);\r\n const name = getStr(bf, 3) || getStr(bf, 2);\r\n if (name) badges.push(name);\r\n }\r\n } catch { }\r\n }\r\n\r\n return {\r\n id,\r\n nickname,\r\n uniqueId: uniqueId || nickname || id,\r\n profilePicture,\r\n badges: badges.length > 0 ? badges : undefined,\r\n };\r\n}\r\n\r\n// ── Battle parsing ──────────────────────────────────────────────────\r\n// Proto: WebcastLinkMicBattle { repeated battleUsers=10 }\r\n// battleUsers → WebcastLinkMicBattleItems { battleGroup=2 }\r\n// battleGroup → WebcastLinkMicBattleGroup { LinkUser user=1 }\r\n//\r\n// Proto: WebcastLinkMicArmies { repeated battleItems=3, battleStatus=7 }\r\n// battleItems → WebcastLinkMicArmiesItems { hostUserId=1, repeated battleGroups=2 }\r\n// battleGroups → WebcastLinkMicArmiesGroup { repeated users=1, points=2 }\r\n\r\nfunction parseBattleTeamFromArmies(itemBuf: Buffer): BattleTeam {\r\n const f = decodeProto(itemBuf);\r\n const hostUserId = String(getInt(f, 1));\r\n let teamScore = 0;\r\n const users: BattleTeamUser[] = [];\r\n\r\n // battleGroups at field 2\r\n const groups = getAllBytes(f, 2);\r\n for (const gb of groups) {\r\n try {\r\n const gf = decodeProto(gb);\r\n const points = getInt(gf, 2);\r\n teamScore += points;\r\n\r\n // users at field 1 (repeated)\r\n const userBufs = getAllBytes(gf, 1);\r\n for (const ub of userBufs) {\r\n try {\r\n const user = parseUser(ub);\r\n users.push({ user, score: points });\r\n } catch { }\r\n }\r\n } catch { }\r\n }\r\n\r\n return { hostUserId, score: teamScore, users };\r\n}\r\n\r\n// ── Message-specific parsers ────────────────────────────────────────\r\n\r\nexport function parseWebcastMessage(method: string, payload: Buffer): LiveEvent {\r\n const f = decodeProto(payload);\r\n const base = { timestamp: Date.now(), msgId: '' };\r\n\r\n // Try to extract msgId from MessageType (field 1 submessage, field 4 = timestamp)\r\n const typeBuf = getBytes(f, 1);\r\n if (typeBuf) {\r\n try {\r\n const tf = decodeProto(typeBuf);\r\n const ts = getInt(tf, 4);\r\n if (ts) base.timestamp = ts;\r\n } catch { }\r\n }\r\n\r\n switch (method) {\r\n // Proto: WebcastChatMessage { MessageType type=1, User user=2, string comment=3 }\r\n case 'WebcastChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'chat' as const, user, comment: getStr(f, 3) };\r\n }\r\n\r\n // Proto: WebcastMemberMessage { User user=2, WebcastMessageEvent event=1 }\r\n case 'WebcastMemberMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let action = 1;\r\n const eventBuf = getBytes(f, 1);\r\n if (eventBuf) {\r\n const ef = decodeProto(eventBuf);\r\n const detailBuf = getBytes(ef, 8);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n const label = getStr(df, 2);\r\n if (label.includes('followed')) action = 2;\r\n else if (label.includes('share')) action = 3;\r\n }\r\n }\r\n return { ...base, type: 'member' as const, user, action };\r\n }\r\n\r\n // Proto: WebcastLikeMessage { User user=5, WebcastMessageEvent event=1, int32 likeCount=2, int32 totalLikeCount=3 }\r\n case 'WebcastLikeMessage': {\r\n const userBuf = getBytes(f, 5);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return {\r\n ...base, type: 'like' as const, user,\r\n likeCount: getInt(f, 2),\r\n totalLikes: getInt(f, 3),\r\n };\r\n }\r\n\r\n // Proto: WebcastGiftMessage {\r\n // User user=7, int32 giftId=2, int32 repeatCount=5, int32 repeatEnd=9,\r\n // GiftDetails giftDetails=15, GiftExtra giftExtra=23\r\n // }\r\n // GiftDetails { GiftImage giftImage=1, string giftName=16, string describe=2,\r\n // int32 giftType=11, int32 diamondCount=12 }\r\n // GiftExtra { uint64 timestamp=6, uint64 toUserId=8 }\r\n case 'WebcastGiftMessage': {\r\n const userBuf = getBytes(f, 7);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n const giftId = getInt(f, 2);\r\n const repeatCount = getInt(f, 5);\r\n const repeatEnd = getInt(f, 9) === 1;\r\n\r\n let giftName = '', diamondCount = 0, giftType = 0;\r\n let giftImageUrl = '';\r\n const detailsBuf = getBytes(f, 15);\r\n if (detailsBuf) {\r\n const df = decodeProto(detailsBuf);\r\n giftName = getStr(df, 16) || getStr(df, 2);\r\n diamondCount = getInt(df, 12);\r\n giftType = getInt(df, 11);\r\n\r\n const imgBuf = getBytes(df, 1);\r\n if (imgBuf) {\r\n const imgf = decodeProto(imgBuf);\r\n giftImageUrl = getStr(imgf, 1);\r\n }\r\n }\r\n\r\n let toUserId = '';\r\n const extraBuf = getBytes(f, 23);\r\n if (extraBuf) {\r\n const ef = decodeProto(extraBuf);\r\n toUserId = String(getInt(ef, 8));\r\n }\r\n\r\n const groupId = toUserId || getStr(f, 11);\r\n\r\n return {\r\n ...base, type: 'gift' as const, user, giftId, giftName, diamondCount,\r\n repeatCount, repeatEnd, combo: repeatCount > 1 && !repeatEnd,\r\n giftType, groupId,\r\n };\r\n }\r\n\r\n // Proto: WebcastSocialMessage { User user=2, WebcastMessageEvent event=1 }\r\n case 'WebcastSocialMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let action = 'follow';\r\n const eventBuf = getBytes(f, 1);\r\n if (eventBuf) {\r\n const ef = decodeProto(eventBuf);\r\n const detailBuf = getBytes(ef, 8);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n const label = getStr(df, 2);\r\n if (label.includes('share')) action = 'share';\r\n else if (label.includes('follow')) action = 'follow';\r\n const displayType = getStr(df, 1);\r\n if (displayType === 'pm_mt_msg_viewer_share') action = 'share';\r\n }\r\n }\r\n return { ...base, type: 'social' as const, user, action };\r\n }\r\n\r\n // Proto: WebcastRoomUserSeqMessage { int32 viewerCount=3 }\r\n case 'WebcastRoomUserSeqMessage': {\r\n const viewerCount = getInt(f, 3) || getInt(f, 2);\r\n const totalViewers = getInt(f, 1) || viewerCount;\r\n return { ...base, type: 'roomUserSeq' as const, totalViewers, viewerCount };\r\n }\r\n\r\n // Proto: WebcastLinkMicBattle { repeated WebcastLinkMicBattleItems battleUsers=10 }\r\n // battleUsers → { battleGroup=2 → { LinkUser user=1 } }\r\n case 'WebcastLinkMicBattle': {\r\n const battleId = String(getInt(f, 1) || '');\r\n const status = getInt(f, 2) || 1;\r\n const battleDuration = getInt(f, 3);\r\n const teams: BattleTeam[] = [];\r\n\r\n // battleUsers at field 10\r\n const battleUserBufs = getAllBytes(f, 10);\r\n for (const bub of battleUserBufs) {\r\n try {\r\n const bf = decodeProto(bub);\r\n const groupBuf = getBytes(bf, 2);\r\n if (groupBuf) {\r\n const gf = decodeProto(groupBuf);\r\n const linkUserBuf = getBytes(gf, 1);\r\n if (linkUserBuf) {\r\n const user = parseUser(linkUserBuf);\r\n teams.push({\r\n hostUserId: user.id,\r\n score: 0,\r\n users: [{ user, score: 0 }],\r\n });\r\n }\r\n }\r\n } catch { }\r\n }\r\n\r\n // Also try field 7 as fallback (some message versions)\r\n if (teams.length === 0) {\r\n const teamBufs7 = getAllBytes(f, 7);\r\n for (const tb of teamBufs7) {\r\n try {\r\n teams.push(parseBattleTeamFromArmies(tb));\r\n } catch { }\r\n }\r\n }\r\n\r\n return { ...base, type: 'battle' as const, battleId, status, battleDuration, teams };\r\n }\r\n\r\n // Proto: WebcastLinkMicArmies { repeated battleItems=3, int32 battleStatus=7 }\r\n // battleItems → { hostUserId=1, repeated battleGroups=2 }\r\n // battleGroups → { repeated users=1, int32 points=2 }\r\n case 'WebcastLinkMicArmies': {\r\n const battleId = String(getInt(f, 1) || '');\r\n const battleStatus = getInt(f, 7);\r\n const teams: BattleTeam[] = [];\r\n\r\n const itemBufs = getAllBytes(f, 3);\r\n for (const ib of itemBufs) {\r\n try {\r\n teams.push(parseBattleTeamFromArmies(ib));\r\n } catch { }\r\n }\r\n\r\n return {\r\n ...base, type: 'battleArmies' as const, battleId, teams,\r\n status: battleStatus,\r\n };\r\n }\r\n\r\n // Proto: WebcastSubNotifyMessage { User user=2, ... subMonth=3 }\r\n case 'WebcastSubNotifyMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n return { ...base, type: 'subscribe' as const, user, subMonth: getInt(f, 3) };\r\n }\r\n\r\n case 'WebcastEmoteChatMessage': {\r\n const userBuf = getBytes(f, 2);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n let emoteId = '', emoteUrl = '';\r\n const emoteBuf = getBytes(f, 3);\r\n if (emoteBuf) {\r\n const ef = decodeProto(emoteBuf);\r\n emoteId = getStr(ef, 1);\r\n const imageBuf = getBytes(ef, 2);\r\n if (imageBuf) {\r\n const imgFields = decodeProto(imageBuf);\r\n emoteUrl = getStr(imgFields, 1);\r\n }\r\n }\r\n return { ...base, type: 'emoteChat' as const, user, emoteId, emoteUrl };\r\n }\r\n\r\n case 'WebcastEnvelopeMessage': {\r\n const envelopeId = String(getInt(f, 1) || getStr(f, 1));\r\n return { ...base, type: 'envelope' as const, envelopeId, diamondCount: getInt(f, 3) };\r\n }\r\n\r\n // Proto: WebcastQuestionNewMessage { MessageType type=1, QuestionDetails questionDetails=2 }\r\n // QuestionDetails { string questionText=2, User user=5 }\r\n case 'WebcastQuestionNewMessage': {\r\n let questionText = '', user: TikTokUser = { id: '0', nickname: '', uniqueId: '' };\r\n const detailBuf = getBytes(f, 2);\r\n if (detailBuf) {\r\n const df = decodeProto(detailBuf);\r\n questionText = getStr(df, 2);\r\n const userBuf = getBytes(df, 5);\r\n if (userBuf) user = parseUser(userBuf);\r\n }\r\n return { ...base, type: 'question' as const, user, questionText };\r\n }\r\n\r\n case 'WebcastRankUpdateMessage':\r\n case 'WebcastHourlyRankMessage': {\r\n const rankType = getStr(f, 1) || `rank_${getInt(f, 1)}`;\r\n const rankList: Array<{ user: TikTokUser; rank: number; score: number }> = [];\r\n const listBufs = getAllBytes(f, 2);\r\n for (const lb of listBufs) {\r\n try {\r\n const rf = decodeProto(lb);\r\n const userBuf = getBytes(rf, 1);\r\n const rank = getInt(rf, 2);\r\n const score = getInt(rf, 3);\r\n const user = userBuf ? parseUser(userBuf) : { id: '0', nickname: '', uniqueId: '' };\r\n rankList.push({ user, rank, score });\r\n } catch { }\r\n }\r\n return { ...base, type: 'rankUpdate' as const, rankType, rankList };\r\n }\r\n\r\n // Proto: WebcastControlMessage { int32 action=2 }\r\n case 'WebcastControlMessage':\r\n return { ...base, type: 'control' as const, action: getInt(f, 2) || getInt(f, 1) };\r\n\r\n case 'WebcastRoomMessage':\r\n case 'RoomMessage':\r\n return { ...base, type: 'room' as const, status: getInt(f, 2) };\r\n\r\n // Proto: WebcastLiveIntroMessage { uint64 id=2, string description=4, User user=5 }\r\n case 'WebcastLiveIntroMessage': {\r\n const roomId = String(getInt(f, 2));\r\n const title = getStr(f, 4) || getStr(f, 2);\r\n return { ...base, type: 'liveIntro' as const, roomId, title };\r\n }\r\n\r\n case 'WebcastLinkMicMethod':\r\n case 'WebcastLinkmicBattleTaskMessage': {\r\n const action = getStr(f, 1) || `action_${getInt(f, 1)}`;\r\n const users: TikTokUser[] = [];\r\n const userBufs = getAllBytes(f, 2);\r\n for (const ub of userBufs) {\r\n try { users.push(parseUser(ub)); } catch { }\r\n }\r\n return { ...base, type: 'linkMic' as const, action, users };\r\n }\r\n\r\n default:\r\n return { ...base, type: 'unknown' as const, method };\r\n }\r\n}\r\n\r\nexport function parseWebcastResponse(payload: Buffer): LiveEvent[] {\r\n const events: LiveEvent[] = [];\r\n const respFields = decodeProto(payload);\r\n\r\n for (const mf of respFields.filter(f => f.fn === 1 && f.wt === 2)) {\r\n const msgBuf = mf.value as Buffer;\r\n const msgFields = decodeProto(msgBuf);\r\n const method = getStr(msgFields, 1);\r\n const innerPayload = getBytes(msgFields, 2);\r\n if (!method || !innerPayload) continue;\r\n\r\n try {\r\n events.push(parseWebcastMessage(method, innerPayload));\r\n } catch { }\r\n }\r\n\r\n return events;\r\n}\r\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tiktool/live",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "TikTok LIVE API Client — Real-time chat, gifts, viewers & events from any TikTok livestream. Direct WebSocket connection.",
5
5
  "author": "tiktool",
6
6
  "license": "MIT",