@tiktool/live 2.6.1 → 2.6.2

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.js CHANGED
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ TikTokCaptions: () => TikTokCaptions,
33
34
  TikTokLive: () => TikTokLive,
34
35
  getRanklist: () => getRanklist,
35
36
  getRegionalRanklist: () => getRegionalRanklist
@@ -335,8 +336,10 @@ function parseBattleTeamFromArmies(itemBuf) {
335
336
  const userBufs = getAllBytes(gf, 1);
336
337
  for (const ub of userBufs) {
337
338
  try {
339
+ const userFields = decodeProto(ub);
340
+ const individualScore = getInt(userFields, 2);
338
341
  const user = parseUser(ub);
339
- users.push({ user, score: points });
342
+ users.push({ user, score: individualScore });
340
343
  } catch {
341
344
  }
342
345
  }
@@ -1167,6 +1170,206 @@ var TikTokLive = class extends import_events.EventEmitter {
1167
1170
  }
1168
1171
  };
1169
1172
 
1173
+ // src/captions.ts
1174
+ var import_events2 = require("events");
1175
+ var import_ws2 = __toESM(require("ws"));
1176
+ var DEFAULT_CAPTIONS_SERVER = "wss://api.tik.tools";
1177
+ var TikTokCaptions = class extends import_events2.EventEmitter {
1178
+ ws = null;
1179
+ _connected = false;
1180
+ intentionalClose = false;
1181
+ reconnectAttempts = 0;
1182
+ uniqueId;
1183
+ apiKey;
1184
+ serverUrl;
1185
+ autoReconnect;
1186
+ maxReconnectAttempts;
1187
+ debug;
1188
+ _translate;
1189
+ _diarization;
1190
+ _maxDurationMinutes;
1191
+ _language;
1192
+ constructor(options) {
1193
+ super();
1194
+ this.uniqueId = options.uniqueId.replace(/^@/, "");
1195
+ if (!options.apiKey) throw new Error("apiKey is required. Get a free key at https://tik.tools");
1196
+ this.apiKey = options.apiKey;
1197
+ this._language = options.language || "";
1198
+ this._translate = options.translate || "";
1199
+ this._diarization = options.diarization ?? true;
1200
+ this._maxDurationMinutes = options.maxDurationMinutes ?? 60;
1201
+ this.serverUrl = (options.signServerUrl || DEFAULT_CAPTIONS_SERVER).replace(/\/$/, "");
1202
+ this.autoReconnect = options.autoReconnect ?? true;
1203
+ this.maxReconnectAttempts = options.maxReconnectAttempts ?? 5;
1204
+ this.debug = options.debug ?? false;
1205
+ }
1206
+ /**
1207
+ * Start real-time captions for the configured TikTok user.
1208
+ * Connects to the captions WebSocket relay and begins transcription
1209
+ * once the user goes live (or immediately if already live).
1210
+ */
1211
+ async start() {
1212
+ this.intentionalClose = false;
1213
+ const wsUrl = this.buildWsUrl();
1214
+ if (this.debug) console.log(`[Captions] Connecting to ${wsUrl}`);
1215
+ return new Promise((resolve, reject) => {
1216
+ this.ws = new import_ws2.default(wsUrl);
1217
+ this.ws.on("open", () => {
1218
+ this._connected = true;
1219
+ this.reconnectAttempts = 0;
1220
+ if (this.debug) console.log("[Captions] Connected");
1221
+ this.emit("connected");
1222
+ resolve();
1223
+ });
1224
+ this.ws.on("message", (data) => {
1225
+ this.handleMessage(typeof data === "string" ? data : data.toString());
1226
+ });
1227
+ this.ws.on("close", (code, reason) => {
1228
+ this._connected = false;
1229
+ const reasonStr = reason?.toString() || "";
1230
+ if (this.debug) console.log(`[Captions] Disconnected: ${code} ${reasonStr}`);
1231
+ this.emit("disconnected", code, reasonStr);
1232
+ if (!this.intentionalClose && this.autoReconnect && this.reconnectAttempts < this.maxReconnectAttempts) {
1233
+ this.reconnectAttempts++;
1234
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts - 1), 3e4);
1235
+ if (this.debug) console.log(`[Captions] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
1236
+ setTimeout(() => this.start().catch((e) => this.emit("error", { code: "RECONNECT_FAILED", message: e.message })), delay);
1237
+ }
1238
+ });
1239
+ this.ws.on("error", (err) => {
1240
+ this.emit("error", { code: "WS_ERROR", message: err.message });
1241
+ if (!this._connected) reject(err);
1242
+ });
1243
+ });
1244
+ }
1245
+ /**
1246
+ * Stop captions and disconnect.
1247
+ */
1248
+ stop() {
1249
+ this.intentionalClose = true;
1250
+ if (this.ws) {
1251
+ this.send({ action: "stop" });
1252
+ this.ws.close(1e3);
1253
+ this.ws = null;
1254
+ }
1255
+ this._connected = false;
1256
+ }
1257
+ /**
1258
+ * Switch the translation target language on-the-fly.
1259
+ * Causes a brief interruption while the transcription engine reconfigures.
1260
+ */
1261
+ setLanguage(language) {
1262
+ this._language = language;
1263
+ this.send({ action: "set_language", language });
1264
+ }
1265
+ /**
1266
+ * Request a credit balance update from the server.
1267
+ */
1268
+ getCredits() {
1269
+ this.send({ action: "get_credits" });
1270
+ }
1271
+ /** Whether the WebSocket is currently connected */
1272
+ get connected() {
1273
+ return this._connected;
1274
+ }
1275
+ /** The current target language */
1276
+ get language() {
1277
+ return this._language;
1278
+ }
1279
+ on(event, listener) {
1280
+ return super.on(event, listener);
1281
+ }
1282
+ once(event, listener) {
1283
+ return super.once(event, listener);
1284
+ }
1285
+ off(event, listener) {
1286
+ return super.off(event, listener);
1287
+ }
1288
+ emit(event, ...args) {
1289
+ return super.emit(event, ...args);
1290
+ }
1291
+ buildWsUrl() {
1292
+ const base = this.serverUrl.replace(/^http/, "ws");
1293
+ const params = new URLSearchParams({
1294
+ uniqueId: this.uniqueId,
1295
+ apiKey: this.apiKey
1296
+ });
1297
+ if (this._language) params.set("language", this._language);
1298
+ if (this._translate) params.set("translate", this._translate);
1299
+ if (this._diarization !== void 0) params.set("diarization", String(this._diarization));
1300
+ if (this._maxDurationMinutes) params.set("max_duration_minutes", String(this._maxDurationMinutes));
1301
+ return `${base}/captions?${params}`;
1302
+ }
1303
+ send(msg) {
1304
+ if (this.ws?.readyState === import_ws2.default.OPEN) {
1305
+ this.ws.send(JSON.stringify(msg));
1306
+ }
1307
+ }
1308
+ handleMessage(raw) {
1309
+ try {
1310
+ const msg = JSON.parse(raw);
1311
+ switch (msg.type) {
1312
+ case "caption":
1313
+ this.emit("caption", {
1314
+ text: msg.text,
1315
+ language: msg.language,
1316
+ isFinal: msg.isFinal,
1317
+ confidence: msg.confidence,
1318
+ speaker: msg.speaker,
1319
+ startMs: msg.startMs,
1320
+ endMs: msg.endMs
1321
+ });
1322
+ break;
1323
+ case "translation":
1324
+ this.emit("translation", {
1325
+ text: msg.text,
1326
+ language: msg.language,
1327
+ isFinal: msg.isFinal,
1328
+ confidence: msg.confidence,
1329
+ speaker: msg.speaker
1330
+ });
1331
+ break;
1332
+ case "status":
1333
+ this.emit("status", {
1334
+ status: msg.status,
1335
+ uniqueId: msg.uniqueId,
1336
+ roomId: msg.roomId,
1337
+ language: msg.language,
1338
+ message: msg.message
1339
+ });
1340
+ break;
1341
+ case "credits":
1342
+ this.emit("credits", {
1343
+ remaining: msg.remaining,
1344
+ total: msg.total,
1345
+ used: msg.used,
1346
+ warning: msg.warning
1347
+ });
1348
+ break;
1349
+ case "credits_low":
1350
+ this.emit("credits_low", {
1351
+ remaining: msg.remaining,
1352
+ total: msg.total,
1353
+ percent: msg.percent
1354
+ });
1355
+ break;
1356
+ case "error":
1357
+ this.emit("error", {
1358
+ code: msg.code,
1359
+ message: msg.message
1360
+ });
1361
+ break;
1362
+ default:
1363
+ if (this.debug) {
1364
+ console.log(`[Captions] Unknown message type: ${msg.type}`, msg);
1365
+ }
1366
+ }
1367
+ } catch {
1368
+ if (this.debug) console.error("[Captions] Failed to parse message:", raw);
1369
+ }
1370
+ }
1371
+ };
1372
+
1170
1373
  // src/api.ts
1171
1374
  var DEFAULT_SIGN_SERVER2 = "https://api.tik.tools";
1172
1375
  var PAGE_CACHE_TTL = 5 * 60 * 1e3;
@@ -1224,6 +1427,7 @@ async function getRegionalRanklist(opts) {
1224
1427
  }
1225
1428
  // Annotate the CommonJS export names for ESM import in node:
1226
1429
  0 && (module.exports = {
1430
+ TikTokCaptions,
1227
1431
  TikTokLive,
1228
1432
  getRanklist,
1229
1433
  getRegionalRanklist