tokwatchr 0.7.0 → 0.7.1
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/cli/index.mjs +26 -21
- package/package.json +1 -1
- package/src/cli/commands/download.ts +9 -4
- package/src/cli/commands/watch.ts +15 -5
package/dist/cli/index.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import { cac } from "cac";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
3
4
|
import pc from "picocolors";
|
|
4
5
|
import { Impit } from "impit";
|
|
5
6
|
import { spawn, spawnSync } from "node:child_process";
|
|
6
7
|
import { EventEmitter } from "node:events";
|
|
7
8
|
import { createWriteStream, existsSync, mkdirSync } from "node:fs";
|
|
8
|
-
import { join } from "node:path";
|
|
9
9
|
//#region package.json
|
|
10
|
-
var version = "0.7.
|
|
10
|
+
var version = "0.7.1";
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/api/client.ts
|
|
13
13
|
/**
|
|
@@ -1250,9 +1250,7 @@ function formatSpeed(bytesPerSec) {
|
|
|
1250
1250
|
async function executeDownload(username, options) {
|
|
1251
1251
|
let downloader;
|
|
1252
1252
|
const onSignal = async () => {
|
|
1253
|
-
console.log(`\n\n ${pc.red("Stopping...")}`);
|
|
1254
1253
|
await downloader.stop();
|
|
1255
|
-
process.exit(0);
|
|
1256
1254
|
};
|
|
1257
1255
|
process.on("SIGINT", onSignal);
|
|
1258
1256
|
process.on("SIGTERM", onSignal);
|
|
@@ -1279,7 +1277,7 @@ async function executeDownload(username, options) {
|
|
|
1279
1277
|
process.stderr.write(`\n ${pc.dim("Remuxing...")}`);
|
|
1280
1278
|
break;
|
|
1281
1279
|
case "completed":
|
|
1282
|
-
process.stderr.write(`\r ${pc.green("Remuxed:")} ${info.outputPath}\n`);
|
|
1280
|
+
process.stderr.write(`\r ${pc.green("Remuxed:")} ${basename(info.outputPath ?? "")}\n`);
|
|
1283
1281
|
break;
|
|
1284
1282
|
case "failed":
|
|
1285
1283
|
process.stderr.write(`\n ${pc.yellow("Remux failed, keeping .ts as fallback")}\n`);
|
|
@@ -1288,9 +1286,10 @@ async function executeDownload(username, options) {
|
|
|
1288
1286
|
});
|
|
1289
1287
|
downloader.on("complete", (results) => {
|
|
1290
1288
|
process.stderr.write("\n");
|
|
1291
|
-
for (const r of results) console.log(` ${pc.green("Saved:")} ${r.filePath} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`);
|
|
1289
|
+
for (const r of results) console.log(` ${pc.green("Saved:")} ${basename(r.filePath)} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`);
|
|
1292
1290
|
const totalMB = results.reduce((sum, r) => sum + r.sizeMB, 0);
|
|
1293
1291
|
console.log(` Done — ${results.length} segment(s), ${totalMB.toFixed(1)}MB total`);
|
|
1292
|
+
if (results.length > 0) console.log(` ${pc.dim(`Output: ${dirname(results[0]?.filePath ?? "")}/`)}`);
|
|
1294
1293
|
});
|
|
1295
1294
|
try {
|
|
1296
1295
|
await downloader.startRecording();
|
|
@@ -1317,10 +1316,10 @@ async function executeDownload(username, options) {
|
|
|
1317
1316
|
*/
|
|
1318
1317
|
async function executeWatch(username, options) {
|
|
1319
1318
|
let downloader;
|
|
1319
|
+
let stopped = false;
|
|
1320
1320
|
const onSignal = async () => {
|
|
1321
|
-
|
|
1321
|
+
stopped = true;
|
|
1322
1322
|
await downloader.stop();
|
|
1323
|
-
process.exit(0);
|
|
1324
1323
|
};
|
|
1325
1324
|
process.on("SIGINT", onSignal);
|
|
1326
1325
|
process.on("SIGTERM", onSignal);
|
|
@@ -1352,7 +1351,7 @@ async function executeWatch(username, options) {
|
|
|
1352
1351
|
process.stderr.write(`\n ${pc.dim("Remuxing...")}`);
|
|
1353
1352
|
break;
|
|
1354
1353
|
case "completed":
|
|
1355
|
-
process.stderr.write(`\r ${pc.green("Remuxed:")} ${info.outputPath}\n`);
|
|
1354
|
+
process.stderr.write(`\r ${pc.green("Remuxed:")} ${basename(info.outputPath ?? "")}\n`);
|
|
1356
1355
|
break;
|
|
1357
1356
|
case "failed":
|
|
1358
1357
|
process.stderr.write(`\n ${pc.yellow("Remux failed, keeping .ts as fallback")}\n`);
|
|
@@ -1361,26 +1360,32 @@ async function executeWatch(username, options) {
|
|
|
1361
1360
|
});
|
|
1362
1361
|
downloader.on("segment", (result, partNum) => {
|
|
1363
1362
|
process.stderr.write("\n");
|
|
1364
|
-
console.log(` ${pc.green("Segment")} ${partNum}: ${result.filePath} ${pc.dim(`(${formatBytes(result.sizeBytes)}, ${formatDuration(result.duration)})`)}`);
|
|
1363
|
+
console.log(` ${pc.green("Segment")} ${partNum}: ${basename(result.filePath)} ${pc.dim(`(${formatBytes(result.sizeBytes)}, ${formatDuration(result.duration)})`)}`);
|
|
1365
1364
|
});
|
|
1366
1365
|
downloader.on("complete", (results) => {
|
|
1367
1366
|
process.stderr.write("\n");
|
|
1368
|
-
for (const r of results) console.log(` ${pc.green("Saved:")} ${r.filePath} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`);
|
|
1367
|
+
for (const r of results) console.log(` ${pc.green("Saved:")} ${basename(r.filePath)} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`);
|
|
1369
1368
|
const totalMB = results.reduce((sum, r) => sum + r.sizeMB, 0);
|
|
1370
1369
|
console.log(` Done — ${results.length} segment(s), ${totalMB.toFixed(1)}MB total`);
|
|
1370
|
+
if (results.length > 0) console.log(` ${pc.dim(`Output: ${dirname(results[0]?.filePath ?? "")}/`)}`);
|
|
1371
1371
|
});
|
|
1372
1372
|
console.log(`${pc.dim("Waiting for ")}${pc.blue(username)}${pc.dim(" to go live...")}`);
|
|
1373
|
-
while (true)
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
console.
|
|
1379
|
-
|
|
1373
|
+
while (true) {
|
|
1374
|
+
if (stopped) break;
|
|
1375
|
+
try {
|
|
1376
|
+
await downloader.start();
|
|
1377
|
+
if (stopped) break;
|
|
1378
|
+
console.log(`\n ${pc.dim("Stream ended, watching for next...")}`);
|
|
1379
|
+
} catch (error) {
|
|
1380
|
+
if (stopped) break;
|
|
1381
|
+
if (error instanceof UserNotFoundError) {
|
|
1382
|
+
console.error(pc.red("[error]"), "User not found. Check the username and try again.");
|
|
1383
|
+
process.exit(1);
|
|
1384
|
+
}
|
|
1385
|
+
console.error(`\n ${pc.yellow(`[warning] ${error}`)}`);
|
|
1386
|
+
await new Promise((r) => setTimeout(r, 1e4));
|
|
1387
|
+
console.log(` ${pc.dim("Retrying...")}`);
|
|
1380
1388
|
}
|
|
1381
|
-
console.error(`\n ${pc.yellow(`[warning] ${error}`)}`);
|
|
1382
|
-
await new Promise((r) => setTimeout(r, 1e4));
|
|
1383
|
-
console.log(` ${pc.dim("Retrying...")}`);
|
|
1384
1389
|
}
|
|
1385
1390
|
}
|
|
1386
1391
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { basename, dirname } from "node:path";
|
|
1
2
|
import pc from "picocolors";
|
|
2
3
|
import type {
|
|
3
4
|
DownloadResult,
|
|
@@ -28,9 +29,8 @@ export async function executeDownload(
|
|
|
28
29
|
// ─── SIGINT / SIGTERM (registered BEFORE any async work) ─────
|
|
29
30
|
|
|
30
31
|
const onSignal = async () => {
|
|
31
|
-
console.log(`\n\n ${pc.red("Stopping...")}`);
|
|
32
32
|
await downloader.stop();
|
|
33
|
-
process.exit
|
|
33
|
+
// No process.exit — let event loop drain naturally
|
|
34
34
|
};
|
|
35
35
|
process.on("SIGINT", onSignal);
|
|
36
36
|
process.on("SIGTERM", onSignal);
|
|
@@ -68,7 +68,7 @@ export async function executeDownload(
|
|
|
68
68
|
break;
|
|
69
69
|
case "completed":
|
|
70
70
|
process.stderr.write(
|
|
71
|
-
`\r ${pc.green("Remuxed:")} ${info.outputPath}\n`,
|
|
71
|
+
`\r ${pc.green("Remuxed:")} ${basename(info.outputPath ?? "")}\n`,
|
|
72
72
|
);
|
|
73
73
|
break;
|
|
74
74
|
case "failed":
|
|
@@ -83,13 +83,18 @@ export async function executeDownload(
|
|
|
83
83
|
process.stderr.write("\n");
|
|
84
84
|
for (const r of results) {
|
|
85
85
|
console.log(
|
|
86
|
-
` ${pc.green("Saved:")} ${r.filePath} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`,
|
|
86
|
+
` ${pc.green("Saved:")} ${basename(r.filePath)} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`,
|
|
87
87
|
);
|
|
88
88
|
}
|
|
89
89
|
const totalMB = results.reduce((sum, r) => sum + r.sizeMB, 0);
|
|
90
90
|
console.log(
|
|
91
91
|
` Done — ${results.length} segment(s), ${totalMB.toFixed(1)}MB total`,
|
|
92
92
|
);
|
|
93
|
+
if (results.length > 0) {
|
|
94
|
+
console.log(
|
|
95
|
+
` ${pc.dim(`Output: ${dirname(results[0]?.filePath ?? "")}/`)}`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
93
98
|
});
|
|
94
99
|
|
|
95
100
|
// ─── Start ──────────────────────────────────────────────
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { basename, dirname } from "node:path";
|
|
1
2
|
import pc from "picocolors";
|
|
2
3
|
import type {
|
|
3
4
|
DownloadResult,
|
|
@@ -21,13 +22,14 @@ export async function executeWatch(
|
|
|
21
22
|
options: WatchCliOptions,
|
|
22
23
|
): Promise<void> {
|
|
23
24
|
let downloader: TikTokLiveDownloader;
|
|
25
|
+
let stopped = false;
|
|
24
26
|
|
|
25
27
|
// ─── SIGINT / SIGTERM (registered BEFORE any async work) ─────
|
|
26
28
|
|
|
27
29
|
const onSignal = async () => {
|
|
28
|
-
|
|
30
|
+
stopped = true;
|
|
29
31
|
await downloader.stop();
|
|
30
|
-
process.exit
|
|
32
|
+
// No process.exit — let event loop drain naturally
|
|
31
33
|
};
|
|
32
34
|
process.on("SIGINT", onSignal);
|
|
33
35
|
process.on("SIGTERM", onSignal);
|
|
@@ -73,7 +75,7 @@ export async function executeWatch(
|
|
|
73
75
|
break;
|
|
74
76
|
case "completed":
|
|
75
77
|
process.stderr.write(
|
|
76
|
-
`\r ${pc.green("Remuxed:")} ${info.outputPath}\n`,
|
|
78
|
+
`\r ${pc.green("Remuxed:")} ${basename(info.outputPath ?? "")}\n`,
|
|
77
79
|
);
|
|
78
80
|
break;
|
|
79
81
|
case "failed":
|
|
@@ -87,7 +89,7 @@ export async function executeWatch(
|
|
|
87
89
|
downloader.on("segment", (result: DownloadResult, partNum: number) => {
|
|
88
90
|
process.stderr.write("\n");
|
|
89
91
|
console.log(
|
|
90
|
-
` ${pc.green("Segment")} ${partNum}: ${result.filePath} ${pc.dim(`(${formatBytes(result.sizeBytes)}, ${formatDuration(result.duration)})`)}`,
|
|
92
|
+
` ${pc.green("Segment")} ${partNum}: ${basename(result.filePath)} ${pc.dim(`(${formatBytes(result.sizeBytes)}, ${formatDuration(result.duration)})`)}`,
|
|
91
93
|
);
|
|
92
94
|
});
|
|
93
95
|
|
|
@@ -95,13 +97,18 @@ export async function executeWatch(
|
|
|
95
97
|
process.stderr.write("\n");
|
|
96
98
|
for (const r of results) {
|
|
97
99
|
console.log(
|
|
98
|
-
` ${pc.green("Saved:")} ${r.filePath} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`,
|
|
100
|
+
` ${pc.green("Saved:")} ${basename(r.filePath)} ${pc.dim(`(${formatBytes(r.sizeBytes)}, ${formatDuration(r.duration)})`)}`,
|
|
99
101
|
);
|
|
100
102
|
}
|
|
101
103
|
const totalMB = results.reduce((sum, r) => sum + r.sizeMB, 0);
|
|
102
104
|
console.log(
|
|
103
105
|
` Done — ${results.length} segment(s), ${totalMB.toFixed(1)}MB total`,
|
|
104
106
|
);
|
|
107
|
+
if (results.length > 0) {
|
|
108
|
+
console.log(
|
|
109
|
+
` ${pc.dim(`Output: ${dirname(results[0]?.filePath ?? "")}/`)}`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
105
112
|
});
|
|
106
113
|
|
|
107
114
|
// ─── Start (persistent loop) ────────────────────────────
|
|
@@ -111,12 +118,15 @@ export async function executeWatch(
|
|
|
111
118
|
);
|
|
112
119
|
|
|
113
120
|
while (true) {
|
|
121
|
+
if (stopped) break;
|
|
114
122
|
try {
|
|
115
123
|
await downloader.start();
|
|
124
|
+
if (stopped) break;
|
|
116
125
|
// Stream ended — complete event already printed results.
|
|
117
126
|
// Continue watching for the next one.
|
|
118
127
|
console.log(`\n ${pc.dim("Stream ended, watching for next...")}`);
|
|
119
128
|
} catch (error) {
|
|
129
|
+
if (stopped) break;
|
|
120
130
|
if (error instanceof UserNotFoundError) {
|
|
121
131
|
console.error(
|
|
122
132
|
pc.red("[error]"),
|