@tiktool/live 1.1.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 +29 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +310 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +310 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,8 @@ interface GiftEvent extends BaseEvent {
|
|
|
37
37
|
repeatCount: number;
|
|
38
38
|
repeatEnd: boolean;
|
|
39
39
|
combo: boolean;
|
|
40
|
+
giftType: number;
|
|
41
|
+
groupId: string;
|
|
40
42
|
}
|
|
41
43
|
interface SocialEvent extends BaseEvent {
|
|
42
44
|
type: 'social';
|
|
@@ -48,12 +50,27 @@ interface RoomUserSeqEvent extends BaseEvent {
|
|
|
48
50
|
viewerCount: number;
|
|
49
51
|
totalViewers: number;
|
|
50
52
|
}
|
|
53
|
+
interface BattleTeamUser {
|
|
54
|
+
user: TikTokUser;
|
|
55
|
+
score: number;
|
|
56
|
+
}
|
|
57
|
+
interface BattleTeam {
|
|
58
|
+
hostUserId: string;
|
|
59
|
+
score: number;
|
|
60
|
+
users: BattleTeamUser[];
|
|
61
|
+
}
|
|
51
62
|
interface BattleEvent extends BaseEvent {
|
|
52
63
|
type: 'battle';
|
|
64
|
+
battleId: string;
|
|
53
65
|
status: number;
|
|
66
|
+
battleDuration: number;
|
|
67
|
+
teams: BattleTeam[];
|
|
54
68
|
}
|
|
55
69
|
interface BattleArmiesEvent extends BaseEvent {
|
|
56
70
|
type: 'battleArmies';
|
|
71
|
+
battleId: string;
|
|
72
|
+
status: number;
|
|
73
|
+
teams: BattleTeam[];
|
|
57
74
|
}
|
|
58
75
|
interface SubscribeEvent extends BaseEvent {
|
|
59
76
|
type: 'subscribe';
|
|
@@ -64,9 +81,11 @@ interface EmoteChatEvent extends BaseEvent {
|
|
|
64
81
|
type: 'emoteChat';
|
|
65
82
|
user: TikTokUser;
|
|
66
83
|
emoteId: string;
|
|
84
|
+
emoteUrl: string;
|
|
67
85
|
}
|
|
68
86
|
interface EnvelopeEvent extends BaseEvent {
|
|
69
87
|
type: 'envelope';
|
|
88
|
+
envelopeId: string;
|
|
70
89
|
diamondCount: number;
|
|
71
90
|
}
|
|
72
91
|
interface QuestionEvent extends BaseEvent {
|
|
@@ -80,19 +99,26 @@ interface ControlEvent extends BaseEvent {
|
|
|
80
99
|
}
|
|
81
100
|
interface RoomEvent extends BaseEvent {
|
|
82
101
|
type: 'room';
|
|
83
|
-
status:
|
|
102
|
+
status: number;
|
|
84
103
|
}
|
|
85
104
|
interface LiveIntroEvent extends BaseEvent {
|
|
86
105
|
type: 'liveIntro';
|
|
106
|
+
roomId: string;
|
|
87
107
|
title: string;
|
|
88
108
|
}
|
|
89
109
|
interface RankUpdateEvent extends BaseEvent {
|
|
90
110
|
type: 'rankUpdate';
|
|
91
111
|
rankType: string;
|
|
112
|
+
rankList: Array<{
|
|
113
|
+
user: TikTokUser;
|
|
114
|
+
rank: number;
|
|
115
|
+
score: number;
|
|
116
|
+
}>;
|
|
92
117
|
}
|
|
93
118
|
interface LinkMicEvent extends BaseEvent {
|
|
94
119
|
type: 'linkMic';
|
|
95
|
-
action:
|
|
120
|
+
action: string;
|
|
121
|
+
users: TikTokUser[];
|
|
96
122
|
}
|
|
97
123
|
interface UnknownEvent extends BaseEvent {
|
|
98
124
|
type: 'unknown';
|
|
@@ -170,4 +196,4 @@ declare class TikTokLive extends EventEmitter {
|
|
|
170
196
|
private stopHeartbeat;
|
|
171
197
|
}
|
|
172
198
|
|
|
173
|
-
export { type BaseEvent, type BattleArmiesEvent, type BattleEvent, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };
|
|
199
|
+
export { type BaseEvent, type BattleArmiesEvent, type BattleEvent, type BattleTeam, type BattleTeamUser, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ interface GiftEvent extends BaseEvent {
|
|
|
37
37
|
repeatCount: number;
|
|
38
38
|
repeatEnd: boolean;
|
|
39
39
|
combo: boolean;
|
|
40
|
+
giftType: number;
|
|
41
|
+
groupId: string;
|
|
40
42
|
}
|
|
41
43
|
interface SocialEvent extends BaseEvent {
|
|
42
44
|
type: 'social';
|
|
@@ -48,12 +50,27 @@ interface RoomUserSeqEvent extends BaseEvent {
|
|
|
48
50
|
viewerCount: number;
|
|
49
51
|
totalViewers: number;
|
|
50
52
|
}
|
|
53
|
+
interface BattleTeamUser {
|
|
54
|
+
user: TikTokUser;
|
|
55
|
+
score: number;
|
|
56
|
+
}
|
|
57
|
+
interface BattleTeam {
|
|
58
|
+
hostUserId: string;
|
|
59
|
+
score: number;
|
|
60
|
+
users: BattleTeamUser[];
|
|
61
|
+
}
|
|
51
62
|
interface BattleEvent extends BaseEvent {
|
|
52
63
|
type: 'battle';
|
|
64
|
+
battleId: string;
|
|
53
65
|
status: number;
|
|
66
|
+
battleDuration: number;
|
|
67
|
+
teams: BattleTeam[];
|
|
54
68
|
}
|
|
55
69
|
interface BattleArmiesEvent extends BaseEvent {
|
|
56
70
|
type: 'battleArmies';
|
|
71
|
+
battleId: string;
|
|
72
|
+
status: number;
|
|
73
|
+
teams: BattleTeam[];
|
|
57
74
|
}
|
|
58
75
|
interface SubscribeEvent extends BaseEvent {
|
|
59
76
|
type: 'subscribe';
|
|
@@ -64,9 +81,11 @@ interface EmoteChatEvent extends BaseEvent {
|
|
|
64
81
|
type: 'emoteChat';
|
|
65
82
|
user: TikTokUser;
|
|
66
83
|
emoteId: string;
|
|
84
|
+
emoteUrl: string;
|
|
67
85
|
}
|
|
68
86
|
interface EnvelopeEvent extends BaseEvent {
|
|
69
87
|
type: 'envelope';
|
|
88
|
+
envelopeId: string;
|
|
70
89
|
diamondCount: number;
|
|
71
90
|
}
|
|
72
91
|
interface QuestionEvent extends BaseEvent {
|
|
@@ -80,19 +99,26 @@ interface ControlEvent extends BaseEvent {
|
|
|
80
99
|
}
|
|
81
100
|
interface RoomEvent extends BaseEvent {
|
|
82
101
|
type: 'room';
|
|
83
|
-
status:
|
|
102
|
+
status: number;
|
|
84
103
|
}
|
|
85
104
|
interface LiveIntroEvent extends BaseEvent {
|
|
86
105
|
type: 'liveIntro';
|
|
106
|
+
roomId: string;
|
|
87
107
|
title: string;
|
|
88
108
|
}
|
|
89
109
|
interface RankUpdateEvent extends BaseEvent {
|
|
90
110
|
type: 'rankUpdate';
|
|
91
111
|
rankType: string;
|
|
112
|
+
rankList: Array<{
|
|
113
|
+
user: TikTokUser;
|
|
114
|
+
rank: number;
|
|
115
|
+
score: number;
|
|
116
|
+
}>;
|
|
92
117
|
}
|
|
93
118
|
interface LinkMicEvent extends BaseEvent {
|
|
94
119
|
type: 'linkMic';
|
|
95
|
-
action:
|
|
120
|
+
action: string;
|
|
121
|
+
users: TikTokUser[];
|
|
96
122
|
}
|
|
97
123
|
interface UnknownEvent extends BaseEvent {
|
|
98
124
|
type: 'unknown';
|
|
@@ -170,4 +196,4 @@ declare class TikTokLive extends EventEmitter {
|
|
|
170
196
|
private stopHeartbeat;
|
|
171
197
|
}
|
|
172
198
|
|
|
173
|
-
export { type BaseEvent, type BattleArmiesEvent, type BattleEvent, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };
|
|
199
|
+
export { type BaseEvent, type BattleArmiesEvent, type BattleEvent, type BattleTeam, type BattleTeamUser, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EnvelopeEvent, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type QuestionEvent, type RankUpdateEvent, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent };
|
package/dist/index.js
CHANGED
|
@@ -123,6 +123,9 @@ function getInt(fields, fn) {
|
|
|
123
123
|
const f = fields.find((x) => x.fn === fn && x.wt === 0);
|
|
124
124
|
return f ? Number(f.value) : 0;
|
|
125
125
|
}
|
|
126
|
+
function getAllBytes(fields, fn) {
|
|
127
|
+
return fields.filter((x) => x.fn === fn && x.wt === 2).map((x) => x.value);
|
|
128
|
+
}
|
|
126
129
|
function buildHeartbeat(roomId) {
|
|
127
130
|
const payload = encodeField(1, 0, BigInt(roomId));
|
|
128
131
|
return Buffer.concat([
|
|
@@ -156,67 +159,329 @@ function buildAck(id) {
|
|
|
156
159
|
function parseUser(data) {
|
|
157
160
|
const f = decodeProto(data);
|
|
158
161
|
const id = String(getInt(f, 1) || getStr(f, 1));
|
|
159
|
-
const nickname = getStr(f, 3) || getStr(f,
|
|
160
|
-
const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2);
|
|
161
|
-
|
|
162
|
+
const nickname = getStr(f, 3) || getStr(f, 2);
|
|
163
|
+
const uniqueId = getStr(f, 38) || getStr(f, 4) || getStr(f, 2) || "";
|
|
164
|
+
let profilePicture;
|
|
165
|
+
const avatarBuf = getBytes(f, 9) || getBytes(f, 3);
|
|
166
|
+
if (avatarBuf) {
|
|
167
|
+
try {
|
|
168
|
+
const avatarFields = decodeProto(avatarBuf);
|
|
169
|
+
const urlBufs = getAllBytes(avatarFields, 1);
|
|
170
|
+
if (urlBufs.length > 0) profilePicture = urlBufs[0].toString("utf-8");
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
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
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function parseBattleTeamFromArmies(itemBuf) {
|
|
197
|
+
const f = decodeProto(itemBuf);
|
|
198
|
+
const hostUserId = String(getInt(f, 1));
|
|
199
|
+
let teamScore = 0;
|
|
200
|
+
const users = [];
|
|
201
|
+
const groups = getAllBytes(f, 2);
|
|
202
|
+
for (const gb of groups) {
|
|
203
|
+
try {
|
|
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
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return { hostUserId, score: teamScore, users };
|
|
162
219
|
}
|
|
163
220
|
function parseWebcastMessage(method, payload) {
|
|
164
221
|
const f = decodeProto(payload);
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
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
|
+
}
|
|
168
232
|
switch (method) {
|
|
169
|
-
|
|
233
|
+
// Proto: WebcastChatMessage { MessageType type=1, User user=2, string comment=3 }
|
|
234
|
+
case "WebcastChatMessage": {
|
|
235
|
+
const userBuf = getBytes(f, 2);
|
|
236
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
170
237
|
return { ...base, type: "chat", user, comment: getStr(f, 3) };
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
case "
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
238
|
+
}
|
|
239
|
+
// Proto: WebcastMemberMessage { User user=2, WebcastMessageEvent event=1 }
|
|
240
|
+
case "WebcastMemberMessage": {
|
|
241
|
+
const userBuf = getBytes(f, 2);
|
|
242
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
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
|
+
}
|
|
183
254
|
}
|
|
255
|
+
return { ...base, type: "member", user, action };
|
|
256
|
+
}
|
|
257
|
+
// Proto: WebcastLikeMessage { User user=5, WebcastMessageEvent event=1, int32 likeCount=2, int32 totalLikeCount=3 }
|
|
258
|
+
case "WebcastLikeMessage": {
|
|
259
|
+
const userBuf = getBytes(f, 5);
|
|
260
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
261
|
+
return {
|
|
262
|
+
...base,
|
|
263
|
+
type: "like",
|
|
264
|
+
user,
|
|
265
|
+
likeCount: getInt(f, 2),
|
|
266
|
+
totalLikes: getInt(f, 3)
|
|
267
|
+
};
|
|
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 }
|
|
276
|
+
case "WebcastGiftMessage": {
|
|
277
|
+
const userBuf = getBytes(f, 7);
|
|
278
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
279
|
+
const giftId = getInt(f, 2);
|
|
184
280
|
const repeatCount = getInt(f, 5);
|
|
185
281
|
const repeatEnd = getInt(f, 9) === 1;
|
|
186
|
-
|
|
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);
|
|
294
|
+
}
|
|
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);
|
|
303
|
+
return {
|
|
304
|
+
...base,
|
|
305
|
+
type: "gift",
|
|
306
|
+
user,
|
|
307
|
+
giftId,
|
|
308
|
+
giftName,
|
|
309
|
+
diamondCount,
|
|
310
|
+
repeatCount,
|
|
311
|
+
repeatEnd,
|
|
312
|
+
combo: repeatCount > 1 && !repeatEnd,
|
|
313
|
+
giftType,
|
|
314
|
+
groupId
|
|
315
|
+
};
|
|
187
316
|
}
|
|
317
|
+
// Proto: WebcastSocialMessage { User user=2, WebcastMessageEvent event=1 }
|
|
188
318
|
case "WebcastSocialMessage": {
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
319
|
+
const userBuf = getBytes(f, 2);
|
|
320
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
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 };
|
|
336
|
+
}
|
|
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 } }
|
|
345
|
+
case "WebcastLinkMicBattle": {
|
|
346
|
+
const battleId = String(getInt(f, 1) || "");
|
|
347
|
+
const status = getInt(f, 2) || 1;
|
|
348
|
+
const battleDuration = getInt(f, 3);
|
|
349
|
+
const teams = [];
|
|
350
|
+
const battleUserBufs = getAllBytes(f, 10);
|
|
351
|
+
for (const bub of battleUserBufs) {
|
|
352
|
+
try {
|
|
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
|
+
}
|
|
367
|
+
} catch {
|
|
368
|
+
}
|
|
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
|
+
}
|
|
379
|
+
return { ...base, type: "battle", battleId, status, battleDuration, teams };
|
|
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 }
|
|
384
|
+
case "WebcastLinkMicArmies": {
|
|
385
|
+
const battleId = String(getInt(f, 1) || "");
|
|
386
|
+
const battleStatus = getInt(f, 7);
|
|
387
|
+
const teams = [];
|
|
388
|
+
const itemBufs = getAllBytes(f, 3);
|
|
389
|
+
for (const ib of itemBufs) {
|
|
390
|
+
try {
|
|
391
|
+
teams.push(parseBattleTeamFromArmies(ib));
|
|
392
|
+
} catch {
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
...base,
|
|
397
|
+
type: "battleArmies",
|
|
398
|
+
battleId,
|
|
399
|
+
teams,
|
|
400
|
+
status: battleStatus
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
// Proto: WebcastSubNotifyMessage { User user=2, ... subMonth=3 }
|
|
404
|
+
case "WebcastSubNotifyMessage": {
|
|
405
|
+
const userBuf = getBytes(f, 2);
|
|
406
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
407
|
+
return { ...base, type: "subscribe", user, subMonth: getInt(f, 3) };
|
|
408
|
+
}
|
|
409
|
+
case "WebcastEmoteChatMessage": {
|
|
410
|
+
const userBuf = getBytes(f, 2);
|
|
411
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
412
|
+
let emoteId = "", emoteUrl = "";
|
|
413
|
+
const emoteBuf = getBytes(f, 3);
|
|
414
|
+
if (emoteBuf) {
|
|
415
|
+
const ef = decodeProto(emoteBuf);
|
|
416
|
+
emoteId = getStr(ef, 1);
|
|
417
|
+
const imageBuf = getBytes(ef, 2);
|
|
418
|
+
if (imageBuf) {
|
|
419
|
+
const imgFields = decodeProto(imageBuf);
|
|
420
|
+
emoteUrl = getStr(imgFields, 1);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return { ...base, type: "emoteChat", user, emoteId, emoteUrl };
|
|
424
|
+
}
|
|
425
|
+
case "WebcastEnvelopeMessage": {
|
|
426
|
+
const envelopeId = String(getInt(f, 1) || getStr(f, 1));
|
|
427
|
+
return { ...base, type: "envelope", envelopeId, diamondCount: getInt(f, 3) };
|
|
428
|
+
}
|
|
429
|
+
// Proto: WebcastQuestionNewMessage { MessageType type=1, QuestionDetails questionDetails=2 }
|
|
430
|
+
// QuestionDetails { string questionText=2, User user=5 }
|
|
431
|
+
case "WebcastQuestionNewMessage": {
|
|
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 };
|
|
192
441
|
}
|
|
193
|
-
case "WebcastRoomUserSeqMessage":
|
|
194
|
-
return { ...base, type: "roomUserSeq", viewerCount: getInt(f, 3), totalViewers: getInt(f, 4) };
|
|
195
|
-
case "WebcastLinkMicBattle":
|
|
196
|
-
return { ...base, type: "battle", status: getInt(f, 3) };
|
|
197
|
-
case "WebcastLinkMicArmies":
|
|
198
|
-
return { ...base, type: "battleArmies" };
|
|
199
|
-
case "WebcastSubNotifyMessage":
|
|
200
|
-
return { ...base, type: "subscribe", user, subMonth: getInt(f, 8) };
|
|
201
|
-
case "WebcastEmoteChatMessage":
|
|
202
|
-
return { ...base, type: "emoteChat", user, emoteId: getStr(f, 3) };
|
|
203
|
-
case "WebcastEnvelopeMessage":
|
|
204
|
-
return { ...base, type: "envelope", diamondCount: getInt(f, 3) };
|
|
205
|
-
case "WebcastQuestionNewMessage":
|
|
206
|
-
return { ...base, type: "question", user, questionText: getStr(f, 3) };
|
|
207
442
|
case "WebcastRankUpdateMessage":
|
|
208
|
-
case "WebcastHourlyRankMessage":
|
|
209
|
-
|
|
443
|
+
case "WebcastHourlyRankMessage": {
|
|
444
|
+
const rankType = getStr(f, 1) || `rank_${getInt(f, 1)}`;
|
|
445
|
+
const rankList = [];
|
|
446
|
+
const listBufs = getAllBytes(f, 2);
|
|
447
|
+
for (const lb of listBufs) {
|
|
448
|
+
try {
|
|
449
|
+
const rf = decodeProto(lb);
|
|
450
|
+
const userBuf = getBytes(rf, 1);
|
|
451
|
+
const rank = getInt(rf, 2);
|
|
452
|
+
const score = getInt(rf, 3);
|
|
453
|
+
const user = userBuf ? parseUser(userBuf) : { id: "0", nickname: "", uniqueId: "" };
|
|
454
|
+
rankList.push({ user, rank, score });
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return { ...base, type: "rankUpdate", rankType, rankList };
|
|
459
|
+
}
|
|
460
|
+
// Proto: WebcastControlMessage { int32 action=2 }
|
|
210
461
|
case "WebcastControlMessage":
|
|
211
|
-
return { ...base, type: "control", action: getInt(f, 2) };
|
|
462
|
+
return { ...base, type: "control", action: getInt(f, 2) || getInt(f, 1) };
|
|
212
463
|
case "WebcastRoomMessage":
|
|
213
464
|
case "RoomMessage":
|
|
214
|
-
return { ...base, type: "room", status:
|
|
215
|
-
|
|
216
|
-
|
|
465
|
+
return { ...base, type: "room", status: getInt(f, 2) };
|
|
466
|
+
// Proto: WebcastLiveIntroMessage { uint64 id=2, string description=4, User user=5 }
|
|
467
|
+
case "WebcastLiveIntroMessage": {
|
|
468
|
+
const roomId = String(getInt(f, 2));
|
|
469
|
+
const title = getStr(f, 4) || getStr(f, 2);
|
|
470
|
+
return { ...base, type: "liveIntro", roomId, title };
|
|
471
|
+
}
|
|
217
472
|
case "WebcastLinkMicMethod":
|
|
218
|
-
case "WebcastLinkmicBattleTaskMessage":
|
|
219
|
-
|
|
473
|
+
case "WebcastLinkmicBattleTaskMessage": {
|
|
474
|
+
const action = getStr(f, 1) || `action_${getInt(f, 1)}`;
|
|
475
|
+
const users = [];
|
|
476
|
+
const userBufs = getAllBytes(f, 2);
|
|
477
|
+
for (const ub of userBufs) {
|
|
478
|
+
try {
|
|
479
|
+
users.push(parseUser(ub));
|
|
480
|
+
} catch {
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
return { ...base, type: "linkMic", action, users };
|
|
484
|
+
}
|
|
220
485
|
default:
|
|
221
486
|
return { ...base, type: "unknown", method };
|
|
222
487
|
}
|