@tiktool/live 2.10.0 → 2.11.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 +59 -11
- package/dist/index.d.mts +65 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +46 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,22 +97,42 @@ Install `https-proxy-agent` if using `proxy`:
|
|
|
97
97
|
npm install https-proxy-agent
|
|
98
98
|
```
|
|
99
99
|
|
|
100
|
-
### Mode 2 — Relayed (via our proxy pool
|
|
100
|
+
### Mode 2 — Relayed (via our proxy pool)
|
|
101
101
|
|
|
102
102
|
```
|
|
103
|
-
Your App ◀──── wss://api.tik.tools
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
103
|
+
Your App ◀──── wss://api.tik.tools/?... ──── tik.tools
|
|
104
|
+
│
|
|
105
|
+
│ WS via
|
|
106
|
+
│ rotated proxies
|
|
107
|
+
▼
|
|
108
|
+
TikTok
|
|
109
109
|
```
|
|
110
110
|
|
|
111
111
|
- **TikTok sees our IPs** (rotated across hundreds of Webshare + residential proxies).
|
|
112
112
|
- We absorb every per-IP rate-limit hit. Survives any block automatically.
|
|
113
113
|
- Best for **30+ concurrent streams**, low-budget setups, or anyone who doesn't want their own IP fingerprinted by TikTok.
|
|
114
|
-
|
|
115
|
-
|
|
114
|
+
|
|
115
|
+
**Easiest — same SDK, one option:**
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { TikTokLive } from '@tiktool/live';
|
|
119
|
+
|
|
120
|
+
const live = new TikTokLive({
|
|
121
|
+
uniqueId: 'creator_username',
|
|
122
|
+
apiKey: 'YOUR_KEY',
|
|
123
|
+
mode: 'relayed', // ← that's it
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
live.on('chat', e => console.log(`${e.user.uniqueId}: ${e.comment}`));
|
|
127
|
+
live.on('gift', e => console.log(`${e.user.uniqueId} sent ${e.giftName}`));
|
|
128
|
+
live.on('battleArmies', e => console.log(e));
|
|
129
|
+
|
|
130
|
+
await live.connect();
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Event names + payload shapes are **identical to Direct mode**. Switch back and forth by toggling `mode`.
|
|
134
|
+
|
|
135
|
+
**Advanced — raw WebSocket (no SDK, your own client):**
|
|
116
136
|
|
|
117
137
|
```typescript
|
|
118
138
|
import WebSocket from 'ws';
|
|
@@ -124,12 +144,12 @@ const ws = new WebSocket(
|
|
|
124
144
|
ws.on('message', raw => {
|
|
125
145
|
const msg = JSON.parse(raw.toString());
|
|
126
146
|
if (msg.event === 'chat') console.log(msg.data.user.uniqueId, msg.data.comment);
|
|
127
|
-
if (msg.event === 'gift') console.log(msg.data.user.uniqueId, msg.data.giftName
|
|
147
|
+
if (msg.event === 'gift') console.log(msg.data.user.uniqueId, msg.data.giftName);
|
|
128
148
|
if (msg.event === 'battleArmies') console.log(msg.data);
|
|
129
149
|
});
|
|
130
150
|
```
|
|
131
151
|
|
|
132
|
-
|
|
152
|
+
Use this when integrating from a non-Node runtime (Python, Go, Bun, browser) or when you want absolute control over the connection.
|
|
133
153
|
|
|
134
154
|
### Side-by-side
|
|
135
155
|
|
|
@@ -318,6 +338,8 @@ live.on('battle', (e) => {
|
|
|
318
338
|
| `heartbeatInterval` | `number` | `10000` | Heartbeat interval (ms) |
|
|
319
339
|
| `roomId` | `string` | — | Pre-resolved room ID (skips page fetch when paired with `sessionId`) |
|
|
320
340
|
| `sessionId` | `string` | — | Pre-resolved `ttwid` cookie (skips page fetch when paired with `roomId`) |
|
|
341
|
+
| `proxy` | `string` | — | HTTP(S) proxy URL for Direct mode (e.g. `http://USER:PASS@host:port`). Requires `https-proxy-agent`. |
|
|
342
|
+
| `mode` | `'direct' \| 'relayed'` | `'direct'` | Connection mode. See [Connection Modes](#connection-modes). |
|
|
321
343
|
| `debug` | `boolean` | `false` | Debug logging |
|
|
322
344
|
|
|
323
345
|
### Methods
|
|
@@ -331,6 +353,32 @@ live.on('battle', (e) => {
|
|
|
331
353
|
| `eventCount` | `number` | Total events received |
|
|
332
354
|
| `roomId` | `string` | Current room ID |
|
|
333
355
|
|
|
356
|
+
### REST endpoints (companion to the WS SDK)
|
|
357
|
+
|
|
358
|
+
For lookups outside the live event stream, hit the sign server directly with your API key:
|
|
359
|
+
|
|
360
|
+
| Endpoint | Method | Tier | Use case |
|
|
361
|
+
|----------|--------|------|----------|
|
|
362
|
+
| `/webcast/room_id` | POST | sandbox+ | `unique_id` → `room_id` |
|
|
363
|
+
| `/webcast/room_info` | POST | sandbox+ | `unique_id` → `room_id` + `alive` + `title` |
|
|
364
|
+
| `/webcast/check_alive` | GET/POST | sandbox+ | Is `room_id` currently live? |
|
|
365
|
+
| `/webcast/bulk_live_check` | POST | basic+ | Batch check up to 500 users in one call |
|
|
366
|
+
| `/webcast/live_status` | GET | sandbox+ | `unique_id` → live snapshot incl. viewer count |
|
|
367
|
+
| `/webcast/user_profile` | GET | **pro+** | **`unique_id` → numeric `id`, `secUid`, nickname, bio, avatars, follower stats** |
|
|
368
|
+
| `/webcast/resolve_user_ids` | POST | sandbox+ | Batch numeric `userId` → `unique_id` (reverse of `user_profile`) |
|
|
369
|
+
| `/webcast/rankings` | GET | sandbox+ | Top gifters / hourly rank for a room |
|
|
370
|
+
| `/webcast/room_video` | POST | basic+ | Get HLS / FLV stream URLs |
|
|
371
|
+
| `/webcast/ws_credentials` | POST | sandbox+ | Get signed WS URL + ttwid (used by Direct mode under the hood) |
|
|
372
|
+
|
|
373
|
+
**Need the streamer's numeric TikTok ID for a username?**
|
|
374
|
+
|
|
375
|
+
```bash
|
|
376
|
+
curl -H "X-Api-Key: YOUR_KEY" \
|
|
377
|
+
"https://api.tik.tools/webcast/user_profile?unique_id=anyuser"
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Returns full profile JSON. Pro tier and above. Cached server-side for 24h — repeated lookups are free and instant.
|
|
381
|
+
|
|
334
382
|
---
|
|
335
383
|
|
|
336
384
|
## Rate Limits
|
package/dist/index.d.mts
CHANGED
|
@@ -370,6 +370,71 @@ declare class TikTokLive extends EventEmitter {
|
|
|
370
370
|
signServerUrl?: string;
|
|
371
371
|
quality?: string;
|
|
372
372
|
}): Promise<StreamInfo>;
|
|
373
|
+
/**
|
|
374
|
+
* Resolve a TikTok username to the streamer's full public profile —
|
|
375
|
+
* numeric user ID, secUid, nickname, bio, avatars, follower stats.
|
|
376
|
+
*
|
|
377
|
+
* Useful when you need the numeric TikTok ID for a username (the inverse
|
|
378
|
+
* of `resolve_user_ids`, which only goes userId → username).
|
|
379
|
+
*
|
|
380
|
+
* Requires Pro tier+. Cached server-side for 24h.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```ts
|
|
384
|
+
* const profile = await TikTokLive.getUserProfile({
|
|
385
|
+
* uniqueId: 'dalga.ahmedov',
|
|
386
|
+
* apiKey: 'YOUR_KEY',
|
|
387
|
+
* });
|
|
388
|
+
* console.log(profile.id); // "7355610677036581896" (numeric)
|
|
389
|
+
* console.log(profile.nickname); // display name
|
|
390
|
+
* console.log(profile.stats.followerCount); // 12345
|
|
391
|
+
* console.log(profile.avatarLarger); // CDN URL
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
static getUserProfile(options: {
|
|
395
|
+
uniqueId: string;
|
|
396
|
+
apiKey: string;
|
|
397
|
+
signServerUrl?: string;
|
|
398
|
+
/** Set `true` to bypass the 24h server cache (e.g. after the user updated their bio). */
|
|
399
|
+
nocache?: boolean;
|
|
400
|
+
}): Promise<{
|
|
401
|
+
id: string;
|
|
402
|
+
uniqueId: string;
|
|
403
|
+
secUid: string;
|
|
404
|
+
nickname: string;
|
|
405
|
+
signature: string;
|
|
406
|
+
verified: boolean;
|
|
407
|
+
avatarThumb: string;
|
|
408
|
+
avatarMedium: string;
|
|
409
|
+
avatarLarger: string;
|
|
410
|
+
stats: {
|
|
411
|
+
followerCount: number;
|
|
412
|
+
followingCount: number;
|
|
413
|
+
heartCount: number;
|
|
414
|
+
videoCount: number;
|
|
415
|
+
};
|
|
416
|
+
}>;
|
|
417
|
+
/**
|
|
418
|
+
* Instance shortcut — fetch the profile of the streamer this client is
|
|
419
|
+
* connected to (or any other user if `uniqueId` is passed).
|
|
420
|
+
*/
|
|
421
|
+
getUserProfile(uniqueId?: string): Promise<{
|
|
422
|
+
id: string;
|
|
423
|
+
uniqueId: string;
|
|
424
|
+
secUid: string;
|
|
425
|
+
nickname: string;
|
|
426
|
+
signature: string;
|
|
427
|
+
verified: boolean;
|
|
428
|
+
avatarThumb: string;
|
|
429
|
+
avatarMedium: string;
|
|
430
|
+
avatarLarger: string;
|
|
431
|
+
stats: {
|
|
432
|
+
followerCount: number;
|
|
433
|
+
followingCount: number;
|
|
434
|
+
heartCount: number;
|
|
435
|
+
videoCount: number;
|
|
436
|
+
};
|
|
437
|
+
}>;
|
|
373
438
|
on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
374
439
|
once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
375
440
|
off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
package/dist/index.d.ts
CHANGED
|
@@ -370,6 +370,71 @@ declare class TikTokLive extends EventEmitter {
|
|
|
370
370
|
signServerUrl?: string;
|
|
371
371
|
quality?: string;
|
|
372
372
|
}): Promise<StreamInfo>;
|
|
373
|
+
/**
|
|
374
|
+
* Resolve a TikTok username to the streamer's full public profile —
|
|
375
|
+
* numeric user ID, secUid, nickname, bio, avatars, follower stats.
|
|
376
|
+
*
|
|
377
|
+
* Useful when you need the numeric TikTok ID for a username (the inverse
|
|
378
|
+
* of `resolve_user_ids`, which only goes userId → username).
|
|
379
|
+
*
|
|
380
|
+
* Requires Pro tier+. Cached server-side for 24h.
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```ts
|
|
384
|
+
* const profile = await TikTokLive.getUserProfile({
|
|
385
|
+
* uniqueId: 'dalga.ahmedov',
|
|
386
|
+
* apiKey: 'YOUR_KEY',
|
|
387
|
+
* });
|
|
388
|
+
* console.log(profile.id); // "7355610677036581896" (numeric)
|
|
389
|
+
* console.log(profile.nickname); // display name
|
|
390
|
+
* console.log(profile.stats.followerCount); // 12345
|
|
391
|
+
* console.log(profile.avatarLarger); // CDN URL
|
|
392
|
+
* ```
|
|
393
|
+
*/
|
|
394
|
+
static getUserProfile(options: {
|
|
395
|
+
uniqueId: string;
|
|
396
|
+
apiKey: string;
|
|
397
|
+
signServerUrl?: string;
|
|
398
|
+
/** Set `true` to bypass the 24h server cache (e.g. after the user updated their bio). */
|
|
399
|
+
nocache?: boolean;
|
|
400
|
+
}): Promise<{
|
|
401
|
+
id: string;
|
|
402
|
+
uniqueId: string;
|
|
403
|
+
secUid: string;
|
|
404
|
+
nickname: string;
|
|
405
|
+
signature: string;
|
|
406
|
+
verified: boolean;
|
|
407
|
+
avatarThumb: string;
|
|
408
|
+
avatarMedium: string;
|
|
409
|
+
avatarLarger: string;
|
|
410
|
+
stats: {
|
|
411
|
+
followerCount: number;
|
|
412
|
+
followingCount: number;
|
|
413
|
+
heartCount: number;
|
|
414
|
+
videoCount: number;
|
|
415
|
+
};
|
|
416
|
+
}>;
|
|
417
|
+
/**
|
|
418
|
+
* Instance shortcut — fetch the profile of the streamer this client is
|
|
419
|
+
* connected to (or any other user if `uniqueId` is passed).
|
|
420
|
+
*/
|
|
421
|
+
getUserProfile(uniqueId?: string): Promise<{
|
|
422
|
+
id: string;
|
|
423
|
+
uniqueId: string;
|
|
424
|
+
secUid: string;
|
|
425
|
+
nickname: string;
|
|
426
|
+
signature: string;
|
|
427
|
+
verified: boolean;
|
|
428
|
+
avatarThumb: string;
|
|
429
|
+
avatarMedium: string;
|
|
430
|
+
avatarLarger: string;
|
|
431
|
+
stats: {
|
|
432
|
+
followerCount: number;
|
|
433
|
+
followingCount: number;
|
|
434
|
+
heartCount: number;
|
|
435
|
+
videoCount: number;
|
|
436
|
+
};
|
|
437
|
+
}>;
|
|
373
438
|
on<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
374
439
|
once<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
|
375
440
|
off<K extends keyof TikTokLiveEvents>(event: K, listener: TikTokLiveEvents[K]): this;
|
package/dist/index.js
CHANGED
|
@@ -2496,6 +2496,52 @@ var TikTokLive = class _TikTokLive extends import_events.EventEmitter {
|
|
|
2496
2496
|
hlsPullUrl: d.hls_pull_url || void 0
|
|
2497
2497
|
};
|
|
2498
2498
|
}
|
|
2499
|
+
/**
|
|
2500
|
+
* Resolve a TikTok username to the streamer's full public profile —
|
|
2501
|
+
* numeric user ID, secUid, nickname, bio, avatars, follower stats.
|
|
2502
|
+
*
|
|
2503
|
+
* Useful when you need the numeric TikTok ID for a username (the inverse
|
|
2504
|
+
* of `resolve_user_ids`, which only goes userId → username).
|
|
2505
|
+
*
|
|
2506
|
+
* Requires Pro tier+. Cached server-side for 24h.
|
|
2507
|
+
*
|
|
2508
|
+
* @example
|
|
2509
|
+
* ```ts
|
|
2510
|
+
* const profile = await TikTokLive.getUserProfile({
|
|
2511
|
+
* uniqueId: 'dalga.ahmedov',
|
|
2512
|
+
* apiKey: 'YOUR_KEY',
|
|
2513
|
+
* });
|
|
2514
|
+
* console.log(profile.id); // "7355610677036581896" (numeric)
|
|
2515
|
+
* console.log(profile.nickname); // display name
|
|
2516
|
+
* console.log(profile.stats.followerCount); // 12345
|
|
2517
|
+
* console.log(profile.avatarLarger); // CDN URL
|
|
2518
|
+
* ```
|
|
2519
|
+
*/
|
|
2520
|
+
static async getUserProfile(options) {
|
|
2521
|
+
const serverUrl = (options.signServerUrl || DEFAULT_SIGN_SERVER).replace(/\/$/, "");
|
|
2522
|
+
const uname = options.uniqueId.replace(/^@/, "");
|
|
2523
|
+
const qs = new URLSearchParams({ unique_id: uname });
|
|
2524
|
+
if (options.nocache) qs.set("nocache", "1");
|
|
2525
|
+
const resp = await fetch(`${serverUrl}/webcast/user_profile?${qs}`, {
|
|
2526
|
+
headers: { "x-api-key": options.apiKey }
|
|
2527
|
+
});
|
|
2528
|
+
const data = await resp.json();
|
|
2529
|
+
if (data.status_code !== 0 || !data.data?.profile) {
|
|
2530
|
+
throw new Error(data.error || `Failed to get user profile for @${uname}`);
|
|
2531
|
+
}
|
|
2532
|
+
return data.data.profile;
|
|
2533
|
+
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Instance shortcut — fetch the profile of the streamer this client is
|
|
2536
|
+
* connected to (or any other user if `uniqueId` is passed).
|
|
2537
|
+
*/
|
|
2538
|
+
async getUserProfile(uniqueId) {
|
|
2539
|
+
return _TikTokLive.getUserProfile({
|
|
2540
|
+
uniqueId: uniqueId || this.uniqueId,
|
|
2541
|
+
apiKey: this.apiKey,
|
|
2542
|
+
signServerUrl: this.signServerUrl
|
|
2543
|
+
});
|
|
2544
|
+
}
|
|
2499
2545
|
on(event, listener) {
|
|
2500
2546
|
return super.on(event, listener);
|
|
2501
2547
|
}
|