tokwatchr 0.4.3 → 0.4.4
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 +6 -0
- package/dist/index.mjs +24 -3
- package/package.json +1 -1
- package/src/TikTokLiveDownloader.ts +34 -4
package/dist/index.d.mts
CHANGED
|
@@ -237,6 +237,12 @@ declare class TikTokLiveDownloader {
|
|
|
237
237
|
private resolveRoomIdOnce;
|
|
238
238
|
private resolveRoomIdWithRetry;
|
|
239
239
|
private fetchStreamInfo;
|
|
240
|
+
/**
|
|
241
|
+
* Poll for stream info until the stream becomes active.
|
|
242
|
+
* Used in waitForLive mode when the room exists but the stream
|
|
243
|
+
* has not yet started broadcasting.
|
|
244
|
+
*/
|
|
245
|
+
private pollStreamInfo;
|
|
240
246
|
/**
|
|
241
247
|
* Download a single segment. Always downloads to .ts (crash-safe).
|
|
242
248
|
* Does NOT remux — that is handled by remuxSegment() running in the background.
|
package/dist/index.mjs
CHANGED
|
@@ -620,7 +620,7 @@ const DEFAULT_OPTIONS = {
|
|
|
620
620
|
bitrate: null,
|
|
621
621
|
maxDuration: Infinity,
|
|
622
622
|
maxSegmentDuration: Infinity,
|
|
623
|
-
checkInterval:
|
|
623
|
+
checkInterval: 18e4,
|
|
624
624
|
proxyUrl: null,
|
|
625
625
|
cookieJar: null,
|
|
626
626
|
browser: "chrome",
|
|
@@ -773,7 +773,7 @@ var TikTokLiveDownloader = class {
|
|
|
773
773
|
if (!roomId && waitForLive) roomId = await this.resolveRoomIdWithRetry();
|
|
774
774
|
if (!roomId) throw new UserOfflineError(this.username);
|
|
775
775
|
this.setState("waiting");
|
|
776
|
-
const firstInfo = await this.fetchStreamInfo(roomId);
|
|
776
|
+
const firstInfo = waitForLive ? await this.pollStreamInfo(roomId) : await this.fetchStreamInfo(roomId);
|
|
777
777
|
if (!(this.options.maxSegmentDuration > 0 && this.options.maxSegmentDuration < Infinity)) {
|
|
778
778
|
const tsResult = await this.downloadSegment(firstInfo, 1);
|
|
779
779
|
const finalResult = await this.remuxSegment(tsResult);
|
|
@@ -834,7 +834,7 @@ var TikTokLiveDownloader = class {
|
|
|
834
834
|
}
|
|
835
835
|
async resolveRoomIdWithRetry() {
|
|
836
836
|
const interval = this.options.checkInterval;
|
|
837
|
-
const maxInterval = Math.max(interval,
|
|
837
|
+
const maxInterval = Math.max(interval, 18e4);
|
|
838
838
|
while (true) {
|
|
839
839
|
this.abortController.signal?.throwIfAborted();
|
|
840
840
|
const roomId = await this.resolveRoomIdOnce();
|
|
@@ -852,6 +852,27 @@ var TikTokLiveDownloader = class {
|
|
|
852
852
|
return info;
|
|
853
853
|
}
|
|
854
854
|
/**
|
|
855
|
+
* Poll for stream info until the stream becomes active.
|
|
856
|
+
* Used in waitForLive mode when the room exists but the stream
|
|
857
|
+
* has not yet started broadcasting.
|
|
858
|
+
*/
|
|
859
|
+
async pollStreamInfo(roomId) {
|
|
860
|
+
const interval = this.options.checkInterval;
|
|
861
|
+
const maxInterval = Math.max(interval, 18e4);
|
|
862
|
+
while (true) {
|
|
863
|
+
this.abortController.signal?.throwIfAborted();
|
|
864
|
+
try {
|
|
865
|
+
return await this.fetchStreamInfo(roomId);
|
|
866
|
+
} catch (err) {
|
|
867
|
+
if (err instanceof StreamFetchError) {
|
|
868
|
+
await sleep(maxInterval);
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
throw err;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
855
876
|
* Download a single segment. Always downloads to .ts (crash-safe).
|
|
856
877
|
* Does NOT remux — that is handled by remuxSegment() running in the background.
|
|
857
878
|
*/
|
package/package.json
CHANGED
|
@@ -9,7 +9,11 @@ import { resolveRoomId } from "./api/room.js";
|
|
|
9
9
|
import { fetchStreamInfo } from "./api/stream.js";
|
|
10
10
|
import { downloadWithFfmpeg } from "./download/ffmpeg.js";
|
|
11
11
|
import { downloadRawHttp } from "./download/raw-http.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
StreamFetchError,
|
|
14
|
+
UserNotFoundError,
|
|
15
|
+
UserOfflineError,
|
|
16
|
+
} from "./errors.js";
|
|
13
17
|
import type {
|
|
14
18
|
DownloaderState,
|
|
15
19
|
DownloadResult,
|
|
@@ -32,7 +36,7 @@ const DEFAULT_OPTIONS: ResolvedOptions = {
|
|
|
32
36
|
bitrate: null,
|
|
33
37
|
maxDuration: Infinity,
|
|
34
38
|
maxSegmentDuration: Infinity,
|
|
35
|
-
checkInterval:
|
|
39
|
+
checkInterval: 180_000,
|
|
36
40
|
proxyUrl: null,
|
|
37
41
|
cookieJar: null,
|
|
38
42
|
browser: "chrome",
|
|
@@ -259,7 +263,9 @@ export class TikTokLiveDownloader {
|
|
|
259
263
|
|
|
260
264
|
// Phase 2: Get stream info (refreshed per segment to avoid stale URLs)
|
|
261
265
|
this.setState("waiting");
|
|
262
|
-
const firstInfo =
|
|
266
|
+
const firstInfo = waitForLive
|
|
267
|
+
? await this.pollStreamInfo(roomId)
|
|
268
|
+
: await this.fetchStreamInfo(roomId);
|
|
263
269
|
|
|
264
270
|
const segmentEnabled =
|
|
265
271
|
this.options.maxSegmentDuration > 0 &&
|
|
@@ -361,7 +367,7 @@ export class TikTokLiveDownloader {
|
|
|
361
367
|
|
|
362
368
|
private async resolveRoomIdWithRetry(): Promise<string> {
|
|
363
369
|
const interval = this.options.checkInterval;
|
|
364
|
-
const maxInterval = Math.max(interval,
|
|
370
|
+
const maxInterval = Math.max(interval, 180_000);
|
|
365
371
|
|
|
366
372
|
while (true) {
|
|
367
373
|
this.abortController.signal?.throwIfAborted();
|
|
@@ -387,6 +393,30 @@ export class TikTokLiveDownloader {
|
|
|
387
393
|
return info;
|
|
388
394
|
}
|
|
389
395
|
|
|
396
|
+
/**
|
|
397
|
+
* Poll for stream info until the stream becomes active.
|
|
398
|
+
* Used in waitForLive mode when the room exists but the stream
|
|
399
|
+
* has not yet started broadcasting.
|
|
400
|
+
*/
|
|
401
|
+
private async pollStreamInfo(roomId: string): Promise<StreamInfo> {
|
|
402
|
+
const interval = this.options.checkInterval;
|
|
403
|
+
const maxInterval = Math.max(interval, 180_000);
|
|
404
|
+
|
|
405
|
+
while (true) {
|
|
406
|
+
this.abortController.signal?.throwIfAborted();
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
return await this.fetchStreamInfo(roomId);
|
|
410
|
+
} catch (err) {
|
|
411
|
+
if (err instanceof StreamFetchError) {
|
|
412
|
+
await sleep(maxInterval);
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
throw err;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
390
420
|
/**
|
|
391
421
|
* Download a single segment. Always downloads to .ts (crash-safe).
|
|
392
422
|
* Does NOT remux — that is handled by remuxSegment() running in the background.
|