@tiktool/live 2.5.2 → 2.6.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/README.md +5 -5
- package/dist/index.d.mts +581 -3
- package/dist/index.d.ts +581 -3
- package/dist/index.js +82 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +82 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,581 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import * as http from 'http';
|
|
3
|
+
|
|
4
|
+
interface TikTokUser {
|
|
5
|
+
id: string;
|
|
6
|
+
nickname: string;
|
|
7
|
+
uniqueId: string;
|
|
8
|
+
profilePicture?: string;
|
|
9
|
+
profilePictureUrl?: string;
|
|
10
|
+
badges?: string[];
|
|
11
|
+
/** User's gifter/spender level (1-50). Higher = more coins spent platform-wide. */
|
|
12
|
+
payGrade?: number;
|
|
13
|
+
}
|
|
14
|
+
interface BaseEvent {
|
|
15
|
+
type: string;
|
|
16
|
+
timestamp: number;
|
|
17
|
+
msgId: string;
|
|
18
|
+
}
|
|
19
|
+
interface ChatEvent extends BaseEvent {
|
|
20
|
+
type: 'chat';
|
|
21
|
+
user: TikTokUser;
|
|
22
|
+
comment: string;
|
|
23
|
+
}
|
|
24
|
+
interface MemberEvent extends BaseEvent {
|
|
25
|
+
type: 'member';
|
|
26
|
+
user: TikTokUser;
|
|
27
|
+
action: number;
|
|
28
|
+
}
|
|
29
|
+
interface LikeEvent extends BaseEvent {
|
|
30
|
+
type: 'like';
|
|
31
|
+
user: TikTokUser;
|
|
32
|
+
likeCount: number;
|
|
33
|
+
totalLikes: number;
|
|
34
|
+
}
|
|
35
|
+
interface GiftEvent extends BaseEvent {
|
|
36
|
+
type: 'gift';
|
|
37
|
+
user: TikTokUser;
|
|
38
|
+
giftId: number;
|
|
39
|
+
giftName: string;
|
|
40
|
+
diamondCount: number;
|
|
41
|
+
repeatCount: number;
|
|
42
|
+
repeatEnd: boolean;
|
|
43
|
+
combo: boolean;
|
|
44
|
+
giftType: number;
|
|
45
|
+
groupId: string;
|
|
46
|
+
giftPictureUrl?: string;
|
|
47
|
+
}
|
|
48
|
+
interface SocialEvent extends BaseEvent {
|
|
49
|
+
type: 'social';
|
|
50
|
+
user: TikTokUser;
|
|
51
|
+
action: 'follow' | 'share' | string;
|
|
52
|
+
}
|
|
53
|
+
interface RoomUserSeqEvent extends BaseEvent {
|
|
54
|
+
type: 'roomUserSeq';
|
|
55
|
+
viewerCount: number;
|
|
56
|
+
totalViewers: number;
|
|
57
|
+
}
|
|
58
|
+
interface BattleTeamUser {
|
|
59
|
+
user: TikTokUser;
|
|
60
|
+
score: number;
|
|
61
|
+
}
|
|
62
|
+
interface BattleTeam {
|
|
63
|
+
hostUserId: string;
|
|
64
|
+
score: number;
|
|
65
|
+
users: BattleTeamUser[];
|
|
66
|
+
hostUser?: TikTokUser;
|
|
67
|
+
}
|
|
68
|
+
interface BattleEvent extends BaseEvent {
|
|
69
|
+
type: 'battle';
|
|
70
|
+
battleId: string;
|
|
71
|
+
status: number;
|
|
72
|
+
battleDuration: number;
|
|
73
|
+
teams: BattleTeam[];
|
|
74
|
+
battleSettings?: {
|
|
75
|
+
startTimeMs?: number;
|
|
76
|
+
duration?: number;
|
|
77
|
+
endTimeMs?: number;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
interface BattleArmiesEvent extends BaseEvent {
|
|
81
|
+
type: 'battleArmies';
|
|
82
|
+
battleId: string;
|
|
83
|
+
status: number;
|
|
84
|
+
teams: BattleTeam[];
|
|
85
|
+
battleSettings?: {
|
|
86
|
+
startTimeMs?: number;
|
|
87
|
+
duration?: number;
|
|
88
|
+
endTimeMs?: number;
|
|
89
|
+
};
|
|
90
|
+
scoreUpdateTime?: number;
|
|
91
|
+
giftSentTime?: number;
|
|
92
|
+
}
|
|
93
|
+
interface BattleTaskEvent extends BaseEvent {
|
|
94
|
+
type: 'battleTask';
|
|
95
|
+
taskAction: number;
|
|
96
|
+
battleRefId: string;
|
|
97
|
+
missionType: string;
|
|
98
|
+
multiplier: number;
|
|
99
|
+
missionDuration: number;
|
|
100
|
+
missionTarget: number;
|
|
101
|
+
remainingSeconds: number;
|
|
102
|
+
endTimestampS: number;
|
|
103
|
+
timerType: number;
|
|
104
|
+
}
|
|
105
|
+
interface BarrageEvent extends BaseEvent {
|
|
106
|
+
type: 'barrage';
|
|
107
|
+
msgType: number;
|
|
108
|
+
subType: number;
|
|
109
|
+
displayType: number;
|
|
110
|
+
duration: number;
|
|
111
|
+
defaultPattern: string;
|
|
112
|
+
content: string;
|
|
113
|
+
}
|
|
114
|
+
interface SubscribeEvent extends BaseEvent {
|
|
115
|
+
type: 'subscribe';
|
|
116
|
+
user: TikTokUser;
|
|
117
|
+
subMonth: number;
|
|
118
|
+
}
|
|
119
|
+
interface EmoteChatEvent extends BaseEvent {
|
|
120
|
+
type: 'emoteChat';
|
|
121
|
+
user: TikTokUser;
|
|
122
|
+
emoteId: string;
|
|
123
|
+
emoteUrl: string;
|
|
124
|
+
emoteName?: string;
|
|
125
|
+
}
|
|
126
|
+
interface EnvelopeEvent extends BaseEvent {
|
|
127
|
+
type: 'envelope';
|
|
128
|
+
envelopeId: string;
|
|
129
|
+
diamondCount: number;
|
|
130
|
+
}
|
|
131
|
+
interface QuestionEvent extends BaseEvent {
|
|
132
|
+
type: 'question';
|
|
133
|
+
user: TikTokUser;
|
|
134
|
+
questionText: string;
|
|
135
|
+
}
|
|
136
|
+
interface ControlEvent extends BaseEvent {
|
|
137
|
+
type: 'control';
|
|
138
|
+
action: number;
|
|
139
|
+
}
|
|
140
|
+
interface RoomEvent extends BaseEvent {
|
|
141
|
+
type: 'room';
|
|
142
|
+
status: number;
|
|
143
|
+
}
|
|
144
|
+
interface LiveIntroEvent extends BaseEvent {
|
|
145
|
+
type: 'liveIntro';
|
|
146
|
+
roomId: string;
|
|
147
|
+
title: string;
|
|
148
|
+
}
|
|
149
|
+
interface RankUpdateEvent extends BaseEvent {
|
|
150
|
+
type: 'rankUpdate';
|
|
151
|
+
rankType: string;
|
|
152
|
+
rankList: Array<{
|
|
153
|
+
user: TikTokUser;
|
|
154
|
+
rank: number;
|
|
155
|
+
score: number;
|
|
156
|
+
}>;
|
|
157
|
+
}
|
|
158
|
+
interface LinkMicEvent extends BaseEvent {
|
|
159
|
+
type: 'linkMic';
|
|
160
|
+
action: string;
|
|
161
|
+
users: TikTokUser[];
|
|
162
|
+
}
|
|
163
|
+
interface UnknownEvent extends BaseEvent {
|
|
164
|
+
type: 'unknown';
|
|
165
|
+
method: string;
|
|
166
|
+
}
|
|
167
|
+
type LiveEvent = ChatEvent | MemberEvent | LikeEvent | GiftEvent | SocialEvent | RoomUserSeqEvent | BattleEvent | BattleArmiesEvent | BattleTaskEvent | BarrageEvent | SubscribeEvent | EmoteChatEvent | EnvelopeEvent | QuestionEvent | ControlEvent | RoomEvent | LiveIntroEvent | RankUpdateEvent | LinkMicEvent | UnknownEvent;
|
|
168
|
+
interface TikTokLiveEvents {
|
|
169
|
+
connected: () => void;
|
|
170
|
+
disconnected: (code: number, reason: string) => void;
|
|
171
|
+
roomInfo: (info: RoomInfo) => void;
|
|
172
|
+
error: (error: Error) => void;
|
|
173
|
+
chat: (event: ChatEvent) => void;
|
|
174
|
+
member: (event: MemberEvent) => void;
|
|
175
|
+
like: (event: LikeEvent) => void;
|
|
176
|
+
gift: (event: GiftEvent) => void;
|
|
177
|
+
social: (event: SocialEvent) => void;
|
|
178
|
+
roomUserSeq: (event: RoomUserSeqEvent) => void;
|
|
179
|
+
battle: (event: BattleEvent) => void;
|
|
180
|
+
battleArmies: (event: BattleArmiesEvent) => void;
|
|
181
|
+
battleTask: (event: BattleTaskEvent) => void;
|
|
182
|
+
barrage: (event: BarrageEvent) => void;
|
|
183
|
+
subscribe: (event: SubscribeEvent) => void;
|
|
184
|
+
emoteChat: (event: EmoteChatEvent) => void;
|
|
185
|
+
envelope: (event: EnvelopeEvent) => void;
|
|
186
|
+
question: (event: QuestionEvent) => void;
|
|
187
|
+
control: (event: ControlEvent) => void;
|
|
188
|
+
room: (event: RoomEvent) => void;
|
|
189
|
+
liveIntro: (event: LiveIntroEvent) => void;
|
|
190
|
+
rankUpdate: (event: RankUpdateEvent) => void;
|
|
191
|
+
linkMic: (event: LinkMicEvent) => void;
|
|
192
|
+
unknown: (event: UnknownEvent) => void;
|
|
193
|
+
event: (event: LiveEvent) => void;
|
|
194
|
+
}
|
|
195
|
+
interface RoomInfo {
|
|
196
|
+
roomId: string;
|
|
197
|
+
wsHost: string;
|
|
198
|
+
clusterRegion: string;
|
|
199
|
+
connectedAt: string;
|
|
200
|
+
ownerUserId?: string;
|
|
201
|
+
}
|
|
202
|
+
interface TikTokLiveOptions {
|
|
203
|
+
uniqueId: string;
|
|
204
|
+
signServerUrl?: string;
|
|
205
|
+
apiKey: string;
|
|
206
|
+
autoReconnect?: boolean;
|
|
207
|
+
maxReconnectAttempts?: number;
|
|
208
|
+
heartbeatInterval?: number;
|
|
209
|
+
debug?: boolean;
|
|
210
|
+
webSocketImpl?: any;
|
|
211
|
+
/**
|
|
212
|
+
* TikTok browser session ID cookie for authenticated connections.
|
|
213
|
+
* Enables ranklist API access and authenticated WebSocket features.
|
|
214
|
+
* Obtain from the user's tiktok.com browser cookies.
|
|
215
|
+
*/
|
|
216
|
+
sessionId?: string;
|
|
217
|
+
/**
|
|
218
|
+
* TikTok target IDC region (e.g. 'useast5').
|
|
219
|
+
* Required when sessionId is provided — must match the account's region.
|
|
220
|
+
*/
|
|
221
|
+
ttTargetIdc?: string;
|
|
222
|
+
/**
|
|
223
|
+
* HTTP agent for routing connections through a proxy.
|
|
224
|
+
* Pass an HttpsProxyAgent (or any http.Agent) to route both the
|
|
225
|
+
* initial HTTP request and WebSocket connection through a proxy.
|
|
226
|
+
*
|
|
227
|
+
* Example:
|
|
228
|
+
* import { HttpsProxyAgent } from 'https-proxy-agent';
|
|
229
|
+
* agent: new HttpsProxyAgent('http://user:pass@host:port')
|
|
230
|
+
*/
|
|
231
|
+
agent?: http.Agent;
|
|
232
|
+
/**
|
|
233
|
+
* If you already know the room ID (e.g. from a leaderboard API),
|
|
234
|
+
* pass it here to skip the HTML page scrape entirely.
|
|
235
|
+
* This avoids geo-restriction issues and speeds up connection.
|
|
236
|
+
*/
|
|
237
|
+
roomId?: string;
|
|
238
|
+
/**
|
|
239
|
+
* Pre-fetched ttwid cookie. When provided along with roomId,
|
|
240
|
+
* the library skips the HTTP fetch to tiktok.com entirely.
|
|
241
|
+
* Fetch once and share across multiple TikTokLive instances.
|
|
242
|
+
*/
|
|
243
|
+
ttwid?: string;
|
|
244
|
+
}
|
|
245
|
+
interface RanklistUser {
|
|
246
|
+
/** TikTok user ID */
|
|
247
|
+
id_str: string;
|
|
248
|
+
/** Display name */
|
|
249
|
+
nickname: string;
|
|
250
|
+
/** Username (@handle) */
|
|
251
|
+
display_id?: string;
|
|
252
|
+
unique_id?: string;
|
|
253
|
+
/** Avatar thumbnail URLs */
|
|
254
|
+
avatar_thumb?: {
|
|
255
|
+
url_list: string[];
|
|
256
|
+
};
|
|
257
|
+
/** Full avatar URLs */
|
|
258
|
+
avatar_medium?: {
|
|
259
|
+
url_list: string[];
|
|
260
|
+
};
|
|
261
|
+
/** Follower info */
|
|
262
|
+
follow_info?: {
|
|
263
|
+
follow_status: number;
|
|
264
|
+
follower_count: number;
|
|
265
|
+
following_count: number;
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Entry from online_audience endpoint (in-room top gifters).
|
|
270
|
+
* Has explicit `rank` (1-based) and `score` fields.
|
|
271
|
+
*/
|
|
272
|
+
interface OnlineAudienceEntry {
|
|
273
|
+
rank: number;
|
|
274
|
+
score: number;
|
|
275
|
+
user: RanklistUser;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Entry from anchor/rank_list endpoint (leaderboard/gifter rankings).
|
|
279
|
+
* Position is the array index. Uses `value` (not `score`).
|
|
280
|
+
*/
|
|
281
|
+
interface AnchorRankListEntry {
|
|
282
|
+
/** Gift value (diamonds/coins) */
|
|
283
|
+
value: number;
|
|
284
|
+
/** Rank category type (e.g. 3 = gifter) */
|
|
285
|
+
rank_type: number;
|
|
286
|
+
/** Time period type (e.g. 1 = hourly) */
|
|
287
|
+
rank_time_type: number;
|
|
288
|
+
/** Auto-thanks message configured by anchor */
|
|
289
|
+
auto_thanks_message?: string;
|
|
290
|
+
/** Schema URL for navigation */
|
|
291
|
+
schema_url?: string;
|
|
292
|
+
/** Highlight DM share status */
|
|
293
|
+
highlight_dm_share_status?: number;
|
|
294
|
+
/** Ranked user data */
|
|
295
|
+
user: RanklistUser;
|
|
296
|
+
}
|
|
297
|
+
interface RanklistSelfInfo {
|
|
298
|
+
rank: number;
|
|
299
|
+
score: number;
|
|
300
|
+
gap_description?: string;
|
|
301
|
+
}
|
|
302
|
+
/** Response from "online_audience" sub-endpoint — in-room top gifters */
|
|
303
|
+
interface OnlineAudienceResponse {
|
|
304
|
+
status_code: number;
|
|
305
|
+
data: {
|
|
306
|
+
ranks: OnlineAudienceEntry[];
|
|
307
|
+
self_info?: RanklistSelfInfo;
|
|
308
|
+
currency?: string;
|
|
309
|
+
total?: number;
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
/** Response from "anchor_rank_list" sub-endpoint — gifter leaderboard */
|
|
313
|
+
interface AnchorRankListResponse {
|
|
314
|
+
status_code: number;
|
|
315
|
+
data: {
|
|
316
|
+
rank_list: AnchorRankListEntry[];
|
|
317
|
+
/** Room where ranks were accumulated */
|
|
318
|
+
latest_room_id_str?: string;
|
|
319
|
+
/** Rank period start (unix timestamp) */
|
|
320
|
+
rank_time_begin?: number;
|
|
321
|
+
/** Rank period end (unix timestamp) */
|
|
322
|
+
rank_time_end?: number;
|
|
323
|
+
/** Whether to show rank summary */
|
|
324
|
+
show_rank_summary?: boolean;
|
|
325
|
+
/** Default rank type for this anchor */
|
|
326
|
+
default_rank_type?: number;
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
/** Entrance tab info from "entrance" sub-endpoint */
|
|
330
|
+
interface EntranceTab {
|
|
331
|
+
title: string;
|
|
332
|
+
rank_type: number;
|
|
333
|
+
list_lynx_type?: number;
|
|
334
|
+
}
|
|
335
|
+
/** Entrance config for a single rank_type */
|
|
336
|
+
interface EntranceInfo {
|
|
337
|
+
rank_type: number;
|
|
338
|
+
/** Whether the anchor appears in this ranking */
|
|
339
|
+
owner_on_rank: boolean;
|
|
340
|
+
/** Anchor's position in this ranking (0-based) */
|
|
341
|
+
owner_rank_idx?: number;
|
|
342
|
+
/** Current score in this ranking */
|
|
343
|
+
current_score?: number;
|
|
344
|
+
/** Countdown in seconds until ranking resets */
|
|
345
|
+
countdown?: number;
|
|
346
|
+
/** Window size in seconds (86400 = daily) */
|
|
347
|
+
window_size?: number;
|
|
348
|
+
/** Unix timestamp when ranking resets */
|
|
349
|
+
reset_time?: number;
|
|
350
|
+
/** Related tab to show when clicking this entrance */
|
|
351
|
+
related_tab_rank_type?: number;
|
|
352
|
+
/** Gap description with points needed to reach a rank */
|
|
353
|
+
affiliated_content?: {
|
|
354
|
+
gap_desc?: {
|
|
355
|
+
default_pattern: string;
|
|
356
|
+
pieces?: Array<{
|
|
357
|
+
string_value: string;
|
|
358
|
+
type: number;
|
|
359
|
+
}>;
|
|
360
|
+
};
|
|
361
|
+
};
|
|
362
|
+
/** Class/League info */
|
|
363
|
+
class_info?: {
|
|
364
|
+
class_type: number;
|
|
365
|
+
star_count: number;
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
interface EntranceResponse {
|
|
369
|
+
status_code: number;
|
|
370
|
+
data: Array<{
|
|
371
|
+
group_type?: number;
|
|
372
|
+
Priority?: number;
|
|
373
|
+
data?: {
|
|
374
|
+
tabs?: EntranceTab[];
|
|
375
|
+
entrances?: EntranceInfo[];
|
|
376
|
+
};
|
|
377
|
+
}>;
|
|
378
|
+
}
|
|
379
|
+
type RanklistResponse = OnlineAudienceResponse | AnchorRankListResponse | EntranceResponse;
|
|
380
|
+
|
|
381
|
+
declare class TikTokLive extends EventEmitter {
|
|
382
|
+
private ws;
|
|
383
|
+
private heartbeatTimer;
|
|
384
|
+
private reconnectAttempts;
|
|
385
|
+
private intentionalClose;
|
|
386
|
+
private _connected;
|
|
387
|
+
private _eventCount;
|
|
388
|
+
private _roomId;
|
|
389
|
+
private _ownerUserId;
|
|
390
|
+
private readonly uniqueId;
|
|
391
|
+
private readonly signServerUrl;
|
|
392
|
+
private readonly apiKey;
|
|
393
|
+
private readonly autoReconnect;
|
|
394
|
+
private readonly maxReconnectAttempts;
|
|
395
|
+
private readonly heartbeatInterval;
|
|
396
|
+
private readonly debug;
|
|
397
|
+
private _sessionId?;
|
|
398
|
+
private _ttTargetIdc?;
|
|
399
|
+
private readonly proxyAgent?;
|
|
400
|
+
private readonly _presetRoomId?;
|
|
401
|
+
private readonly _presetTtwid?;
|
|
402
|
+
constructor(options: TikTokLiveOptions);
|
|
403
|
+
connect(): Promise<void>;
|
|
404
|
+
disconnect(): void;
|
|
405
|
+
get connected(): boolean;
|
|
406
|
+
get eventCount(): number;
|
|
407
|
+
get roomId(): string;
|
|
408
|
+
/** Get the stored session ID (if any) */
|
|
409
|
+
get sessionId(): string | undefined;
|
|
410
|
+
/** Update the session ID at runtime (e.g. after TikTok login) */
|
|
411
|
+
setSession(sessionId: string, ttTargetIdc?: string): void;
|
|
412
|
+
/**
|
|
413
|
+
* Build a cookie header string for authenticated API requests (e.g. ranklist).
|
|
414
|
+
* Returns undefined if no session is set.
|
|
415
|
+
*/
|
|
416
|
+
buildSessionCookieHeader(): string | undefined;
|
|
417
|
+
on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
418
|
+
once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
419
|
+
off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
420
|
+
emit<K extends keyof TikTokLiveEvents>(event: K, ...args: Parameters<TikTokLiveEvents[K]>): boolean;
|
|
421
|
+
private handleFrame;
|
|
422
|
+
private startHeartbeat;
|
|
423
|
+
private stopHeartbeat;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
interface GetRanklistOptions {
|
|
427
|
+
/** API server URL (default: https://api.tik.tools) */
|
|
428
|
+
serverUrl?: string;
|
|
429
|
+
/** API key for authentication */
|
|
430
|
+
apiKey: string;
|
|
431
|
+
/** TikTok username to look up (auto-resolves room_id and anchor_id) */
|
|
432
|
+
uniqueId?: string;
|
|
433
|
+
/** Direct room ID (skip resolution) */
|
|
434
|
+
roomId?: string;
|
|
435
|
+
/** Direct anchor/owner ID (skip resolution) */
|
|
436
|
+
anchorId?: string;
|
|
437
|
+
/**
|
|
438
|
+
* TikTok session cookie string for authentication.
|
|
439
|
+
* Required — ranklist endpoints return 20003 without login.
|
|
440
|
+
* Example: "sessionid=abc123; sid_guard=def456"
|
|
441
|
+
*/
|
|
442
|
+
sessionCookie?: string;
|
|
443
|
+
/**
|
|
444
|
+
* Which ranklist sub-endpoint to call:
|
|
445
|
+
* - "online_audience" (default) — top gifters with scores
|
|
446
|
+
* - "anchor_rank_list" — gifter ranking by rank_type
|
|
447
|
+
* - "entrance" — entrance UI metadata, tabs, gap-to-rank
|
|
448
|
+
*/
|
|
449
|
+
type?: 'online_audience' | 'anchor_rank_list' | 'entrance';
|
|
450
|
+
/**
|
|
451
|
+
* For "anchor_rank_list" type only:
|
|
452
|
+
* - "1" = hourly ranking (default)
|
|
453
|
+
* - "8" = daily ranking
|
|
454
|
+
*/
|
|
455
|
+
rankType?: string;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Fetch ranked user lists from TikTok via the sign server.
|
|
459
|
+
*
|
|
460
|
+
* When `sessionCookie` is provided, the server returns a **sign-and-return**
|
|
461
|
+
* response with a signed URL that you must fetch from your own IP
|
|
462
|
+
* (TikTok sessions are IP-bound). Check for `sign_and_return: true` in
|
|
463
|
+
* the response to detect this mode.
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* const data = await getRanklist({
|
|
468
|
+
* apiKey: 'your-key',
|
|
469
|
+
* uniqueId: 'katarina.live',
|
|
470
|
+
* sessionCookie: 'sessionid=abc; sid_guard=def',
|
|
471
|
+
* type: 'online_audience',
|
|
472
|
+
* });
|
|
473
|
+
*
|
|
474
|
+
* if (data.sign_and_return) {
|
|
475
|
+
* // Fetch the signed URL from YOUR IP with your session cookie
|
|
476
|
+
* const resp = await fetch(data.signed_url, {
|
|
477
|
+
* method: data.method,
|
|
478
|
+
* headers: { ...data.headers, Cookie: sessionCookie },
|
|
479
|
+
* ...(data.body ? { body: data.body } : {}),
|
|
480
|
+
* });
|
|
481
|
+
* const tikData = await resp.json();
|
|
482
|
+
* console.log(tikData); // TikTok's raw response
|
|
483
|
+
* } else {
|
|
484
|
+
* console.log(data); // Direct TikTok response (no session)
|
|
485
|
+
* }
|
|
486
|
+
* ```
|
|
487
|
+
*/
|
|
488
|
+
declare function getRanklist(opts: GetRanklistOptions): Promise<RanklistResponse>;
|
|
489
|
+
|
|
490
|
+
interface GetRegionalRanklistOptions {
|
|
491
|
+
/** API server URL (default: https://api.tik.tools) */
|
|
492
|
+
serverUrl?: string;
|
|
493
|
+
/** API key for authentication (Pro or Ultra tier required) */
|
|
494
|
+
apiKey: string;
|
|
495
|
+
/** TikTok username to look up (auto-resolves room_id and anchor_id) */
|
|
496
|
+
uniqueId?: string;
|
|
497
|
+
/** Direct room ID (skip resolution) */
|
|
498
|
+
roomId?: string;
|
|
499
|
+
/** Direct anchor/owner ID (skip resolution) */
|
|
500
|
+
anchorId?: string;
|
|
501
|
+
/**
|
|
502
|
+
* Ranking period:
|
|
503
|
+
* - "1" = Hourly
|
|
504
|
+
* - "8" = Daily (default)
|
|
505
|
+
* - "15" = Popular LIVE
|
|
506
|
+
* - "16" = League
|
|
507
|
+
*/
|
|
508
|
+
rankType?: '1' | '8' | '15' | '16';
|
|
509
|
+
/**
|
|
510
|
+
* Sub-endpoint type:
|
|
511
|
+
* - "list" (default) — ranked users with scores
|
|
512
|
+
* - "entrance" — available ranking tabs/metadata
|
|
513
|
+
*/
|
|
514
|
+
type?: 'list' | 'entrance';
|
|
515
|
+
/** Gap interval filter (default: "0") */
|
|
516
|
+
gapInterval?: string;
|
|
517
|
+
/**
|
|
518
|
+
* TikTok session cookie string for authentication.
|
|
519
|
+
* Passed to the API server for proxied requests.
|
|
520
|
+
* Example: "sessionid=abc123; sessionid_ss=abc123"
|
|
521
|
+
*/
|
|
522
|
+
sessionCookie?: string;
|
|
523
|
+
/**
|
|
524
|
+
* Client's real IP address (for deployed server scenarios).
|
|
525
|
+
* When running on a remote server, pass the end-user's IP so the
|
|
526
|
+
* API server can proxy the TikTok request from the correct IP.
|
|
527
|
+
*/
|
|
528
|
+
clientIp?: string;
|
|
529
|
+
}
|
|
530
|
+
interface RegionalRanklistSignedResponse {
|
|
531
|
+
/** Always 0 on success */
|
|
532
|
+
status_code: number;
|
|
533
|
+
/** Always "fetch_signed_url" */
|
|
534
|
+
action: string;
|
|
535
|
+
/** The signed TikTok URL to POST */
|
|
536
|
+
signed_url: string;
|
|
537
|
+
/** HTTP method (always POST) */
|
|
538
|
+
method: string;
|
|
539
|
+
/** Required headers for the fetch */
|
|
540
|
+
headers: Record<string, string>;
|
|
541
|
+
/** URL-encoded POST body */
|
|
542
|
+
body: string;
|
|
543
|
+
/** Cookies to include (ttwid etc.) — append your sessionid */
|
|
544
|
+
cookies: string;
|
|
545
|
+
/** Human-readable note */
|
|
546
|
+
note: string;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Get a signed URL for fetching regional LIVE leaderboard data.
|
|
550
|
+
*
|
|
551
|
+
* **Two-step pattern**: TikTok sessions are IP-bound, so instead of
|
|
552
|
+
* server-side fetching, this returns a signed URL with headers/body
|
|
553
|
+
* that you POST from your own IP with your session cookie.
|
|
554
|
+
*
|
|
555
|
+
* Requires **Pro** or **Ultra** API key tier.
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```ts
|
|
559
|
+
* // Step 1: Get signed URL
|
|
560
|
+
* const signed = await getRegionalRanklist({
|
|
561
|
+
* apiKey: 'your-pro-key',
|
|
562
|
+
* roomId: '7607695933891218198',
|
|
563
|
+
* anchorId: '7444599004337652758',
|
|
564
|
+
* rankType: '8', // Daily
|
|
565
|
+
* });
|
|
566
|
+
*
|
|
567
|
+
* // Step 2: Fetch from YOUR IP with YOUR session
|
|
568
|
+
* const resp = await fetch(signed.signed_url, {
|
|
569
|
+
* method: signed.method,
|
|
570
|
+
* headers: { ...signed.headers, Cookie: `sessionid=YOUR_SID; ${signed.cookies}` },
|
|
571
|
+
* body: signed.body,
|
|
572
|
+
* });
|
|
573
|
+
* const { data } = await resp.json();
|
|
574
|
+
* data.rank_view.ranks.forEach((r, i) =>
|
|
575
|
+
* console.log(`${i+1}. ${r.user.nickname} — ${r.score} pts`)
|
|
576
|
+
* );
|
|
577
|
+
* ```
|
|
578
|
+
*/
|
|
579
|
+
declare function getRegionalRanklist(opts: GetRegionalRanklistOptions): Promise<RegionalRanklistSignedResponse>;
|
|
580
|
+
|
|
581
|
+
export { type AnchorRankListEntry, type AnchorRankListResponse, type BarrageEvent, type BaseEvent, type BattleArmiesEvent, type BattleEvent, type BattleTaskEvent, type BattleTeam, type BattleTeamUser, type ChatEvent, type ControlEvent, type EmoteChatEvent, type EntranceInfo, type EntranceResponse, type EntranceTab, type EnvelopeEvent, type GetRanklistOptions, type GetRegionalRanklistOptions, type GiftEvent, type LikeEvent, type LinkMicEvent, type LiveEvent, type LiveIntroEvent, type MemberEvent, type OnlineAudienceEntry, type OnlineAudienceResponse, type QuestionEvent, type RankUpdateEvent, type RanklistResponse, type RanklistSelfInfo, type RanklistUser, type RegionalRanklistSignedResponse, type RoomEvent, type RoomInfo, type RoomUserSeqEvent, type SocialEvent, type SubscribeEvent, TikTokLive, type TikTokLiveEvents, type TikTokLiveOptions, type TikTokUser, type UnknownEvent, getRanklist, getRegionalRanklist };
|