@audd/sdk 1.5.11 → 1.5.12
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 +9 -8
- package/dist/index.cjs +165 -143
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -27
- package/dist/index.d.ts +36 -27
- package/dist/index.js +165 -143
- package/dist/index.js.map +1 -1
- package/dist/longpoll.cjs +39 -18
- package/dist/longpoll.cjs.map +1 -1
- package/dist/longpoll.d.cts +2 -2
- package/dist/longpoll.d.ts +2 -2
- package/dist/longpoll.js +39 -18
- package/dist/longpoll.js.map +1 -1
- package/dist/{longpollCore-ZtFOyojP.d.cts → longpollCore-BXx8PRmC.d.cts} +1 -1
- package/dist/{longpollCore-ZtFOyojP.d.ts → longpollCore-BXx8PRmC.d.ts} +1 -1
- package/package.json +19 -10
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import * as path from 'path';
|
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
|
|
5
5
|
// src/version.ts
|
|
6
|
-
var VERSION = "1.5.
|
|
6
|
+
var VERSION = "1.5.12";
|
|
7
7
|
|
|
8
8
|
// src/errors.ts
|
|
9
9
|
var AudDError = class extends Error {
|
|
@@ -76,6 +76,16 @@ var AudDConnectionError = class extends AudDError {
|
|
|
76
76
|
this.cause = cause;
|
|
77
77
|
}
|
|
78
78
|
};
|
|
79
|
+
var USER_ABORT_ERROR_NAME = "UserAbortError";
|
|
80
|
+
function userAbortError(cause) {
|
|
81
|
+
const err = new Error("Request was cancelled by the caller's AbortSignal");
|
|
82
|
+
err.name = USER_ABORT_ERROR_NAME;
|
|
83
|
+
err.cause = cause;
|
|
84
|
+
return err;
|
|
85
|
+
}
|
|
86
|
+
function isUserAbortError(err) {
|
|
87
|
+
return err !== null && typeof err === "object" && err.name === USER_ABORT_ERROR_NAME;
|
|
88
|
+
}
|
|
79
89
|
var AudDSerializationError = class extends AudDError {
|
|
80
90
|
name = "AudDSerializationError";
|
|
81
91
|
rawText;
|
|
@@ -148,6 +158,55 @@ function raiseFromErrorResponse(body, opts) {
|
|
|
148
158
|
throw new Cls(fields);
|
|
149
159
|
}
|
|
150
160
|
|
|
161
|
+
// src/events.ts
|
|
162
|
+
function safeEmit(hook, event) {
|
|
163
|
+
if (hook === void 0) return;
|
|
164
|
+
try {
|
|
165
|
+
hook(event);
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function emitAround(hook, method, url, fn) {
|
|
170
|
+
const startedAt = Date.now();
|
|
171
|
+
safeEmit(hook, {
|
|
172
|
+
kind: "request",
|
|
173
|
+
method,
|
|
174
|
+
url,
|
|
175
|
+
requestId: null,
|
|
176
|
+
httpStatus: null,
|
|
177
|
+
elapsedMs: null,
|
|
178
|
+
errorCode: null,
|
|
179
|
+
extras: {}
|
|
180
|
+
});
|
|
181
|
+
let resp;
|
|
182
|
+
try {
|
|
183
|
+
resp = await fn();
|
|
184
|
+
} catch (err) {
|
|
185
|
+
safeEmit(hook, {
|
|
186
|
+
kind: "exception",
|
|
187
|
+
method,
|
|
188
|
+
url,
|
|
189
|
+
requestId: null,
|
|
190
|
+
httpStatus: null,
|
|
191
|
+
elapsedMs: Date.now() - startedAt,
|
|
192
|
+
errorCode: null,
|
|
193
|
+
extras: { name: err instanceof Error ? err.name : String(err) }
|
|
194
|
+
});
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
safeEmit(hook, {
|
|
198
|
+
kind: "response",
|
|
199
|
+
method,
|
|
200
|
+
url,
|
|
201
|
+
requestId: resp.requestId,
|
|
202
|
+
httpStatus: resp.httpStatus,
|
|
203
|
+
elapsedMs: Date.now() - startedAt,
|
|
204
|
+
errorCode: null,
|
|
205
|
+
extras: {}
|
|
206
|
+
});
|
|
207
|
+
return resp;
|
|
208
|
+
}
|
|
209
|
+
|
|
151
210
|
// src/userAgent.ts
|
|
152
211
|
function userAgent() {
|
|
153
212
|
const node = typeof process !== "undefined" && process.version ? process.version.replace(/^v/, "") : "unknown";
|
|
@@ -225,6 +284,11 @@ var HttpClient = class {
|
|
|
225
284
|
requestId: response.headers.get("x-request-id"),
|
|
226
285
|
rawText: text
|
|
227
286
|
};
|
|
287
|
+
} catch (err) {
|
|
288
|
+
if (userSignal?.aborted === true && err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
289
|
+
throw userAbortError(err);
|
|
290
|
+
}
|
|
291
|
+
throw err;
|
|
228
292
|
} finally {
|
|
229
293
|
clearTimeout(timer);
|
|
230
294
|
if (userSignal !== void 0) {
|
|
@@ -249,10 +313,8 @@ function asObject(raw) {
|
|
|
249
313
|
}
|
|
250
314
|
return void 0;
|
|
251
315
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
254
|
-
if (o === void 0) throw new TypeError(`${what}: expected object`);
|
|
255
|
-
return o;
|
|
316
|
+
function asObjectLenient(raw) {
|
|
317
|
+
return asObject(raw) ?? {};
|
|
256
318
|
}
|
|
257
319
|
function asString(v) {
|
|
258
320
|
return typeof v === "string" ? v : void 0;
|
|
@@ -356,7 +418,7 @@ var RECOGNITION_KEYS = [
|
|
|
356
418
|
"musicbrainz"
|
|
357
419
|
];
|
|
358
420
|
function parseRecognitionResult(raw) {
|
|
359
|
-
const r =
|
|
421
|
+
const r = asObjectLenient(raw);
|
|
360
422
|
const timecode = asString(r.timecode);
|
|
361
423
|
const audioId = asNumber(r.audio_id);
|
|
362
424
|
const artist = asString(r.artist);
|
|
@@ -431,7 +493,7 @@ var ENTERPRISE_MATCH_KEYS = [
|
|
|
431
493
|
"end_seconds"
|
|
432
494
|
];
|
|
433
495
|
function parseEnterpriseMatch(raw) {
|
|
434
|
-
const r =
|
|
496
|
+
const r = asObjectLenient(raw);
|
|
435
497
|
const score = asNumber(r.score);
|
|
436
498
|
const timecode = asString(r.timecode);
|
|
437
499
|
const songLink = asString(r.song_link);
|
|
@@ -481,8 +543,8 @@ function parseEnterpriseMatch(raw) {
|
|
|
481
543
|
}
|
|
482
544
|
var ENTERPRISE_CHUNK_KEYS = ["songs", "offset"];
|
|
483
545
|
function parseEnterpriseChunkResult(raw) {
|
|
484
|
-
const r =
|
|
485
|
-
const songsRaw = Array.isArray(r.songs) ? r.songs : [];
|
|
546
|
+
const r = asObjectLenient(raw);
|
|
547
|
+
const songsRaw = Array.isArray(r.songs) ? r.songs.filter((s) => asObject(s) !== void 0) : [];
|
|
486
548
|
const offset = asString(r.offset);
|
|
487
549
|
const base = parseOffsetToSeconds(r.offset);
|
|
488
550
|
const songs = songsRaw.map((s) => {
|
|
@@ -502,7 +564,7 @@ function parseEnterpriseChunkResult(raw) {
|
|
|
502
564
|
}
|
|
503
565
|
var STREAM_KEYS = ["radio_id", "url", "stream_running", "longpoll_category"];
|
|
504
566
|
function parseStream(raw) {
|
|
505
|
-
const r =
|
|
567
|
+
const r = asObjectLenient(raw);
|
|
506
568
|
const radioId = asNumber(r.radio_id);
|
|
507
569
|
const url = asString(r.url);
|
|
508
570
|
const streamRunning = asBoolean(r.stream_running);
|
|
@@ -532,7 +594,7 @@ var STREAM_CALLBACK_SONG_KEYS = [
|
|
|
532
594
|
"musicbrainz"
|
|
533
595
|
];
|
|
534
596
|
function parseStreamCallbackSong(raw) {
|
|
535
|
-
const r =
|
|
597
|
+
const r = asObjectLenient(raw);
|
|
536
598
|
const artist = asString(r.artist);
|
|
537
599
|
const title = asString(r.title);
|
|
538
600
|
const score = asNumber(r.score);
|
|
@@ -562,7 +624,7 @@ var STREAM_CALLBACK_MATCH_KEYS = [
|
|
|
562
624
|
"results"
|
|
563
625
|
];
|
|
564
626
|
function parseStreamCallbackMatch(raw) {
|
|
565
|
-
const r =
|
|
627
|
+
const r = asObjectLenient(raw);
|
|
566
628
|
const radioId = asNumber(r.radio_id);
|
|
567
629
|
const resultsRaw = Array.isArray(r.results) ? r.results : [];
|
|
568
630
|
const songs = resultsRaw.filter((x) => asObject(x) !== void 0).map(parseStreamCallbackSong);
|
|
@@ -584,7 +646,7 @@ var STREAM_CALLBACK_NOTIFICATION_KEYS = [
|
|
|
584
646
|
"notification_message"
|
|
585
647
|
];
|
|
586
648
|
function parseStreamCallbackNotification(raw) {
|
|
587
|
-
const r =
|
|
649
|
+
const r = asObjectLenient(raw);
|
|
588
650
|
const radioId = asNumber(r.radio_id);
|
|
589
651
|
const code = asNumber(r.notification_code);
|
|
590
652
|
const message = asString(r.notification_message);
|
|
@@ -608,7 +670,7 @@ var LYRICS_KEYS = [
|
|
|
608
670
|
"media"
|
|
609
671
|
];
|
|
610
672
|
function parseLyricsResult(raw) {
|
|
611
|
-
const r =
|
|
673
|
+
const r = asObjectLenient(raw);
|
|
612
674
|
const artist = asString(r.artist);
|
|
613
675
|
const title = asString(r.title);
|
|
614
676
|
return {
|
|
@@ -704,6 +766,22 @@ async function retry(fn, policy) {
|
|
|
704
766
|
if (haveResp && lastResp !== void 0) return lastResp;
|
|
705
767
|
throw lastError;
|
|
706
768
|
}
|
|
769
|
+
async function runRetried(fn, policy) {
|
|
770
|
+
try {
|
|
771
|
+
return await retry(fn, policy);
|
|
772
|
+
} catch (err) {
|
|
773
|
+
if (isUserAbortError(err)) {
|
|
774
|
+
throw new AudDConnectionError("Request was cancelled by the caller's AbortSignal", err);
|
|
775
|
+
}
|
|
776
|
+
if (err instanceof TypeError) {
|
|
777
|
+
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
778
|
+
}
|
|
779
|
+
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
780
|
+
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
781
|
+
}
|
|
782
|
+
throw err;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
707
785
|
function looksLikeUrl(s) {
|
|
708
786
|
return s.startsWith("http://") || s.startsWith("https://");
|
|
709
787
|
}
|
|
@@ -955,13 +1033,13 @@ function decodeOne(resp) {
|
|
|
955
1033
|
);
|
|
956
1034
|
}
|
|
957
1035
|
const dict = body;
|
|
958
|
-
if (
|
|
1036
|
+
if (asObject(dict.notification) !== void 0) {
|
|
959
1037
|
const notification = parseStreamCallbackNotification(dict.notification);
|
|
960
1038
|
const t = dict["time"];
|
|
961
1039
|
if (typeof t === "number") notification.time = t;
|
|
962
1040
|
return { kind: "notification", notification };
|
|
963
1041
|
}
|
|
964
|
-
if (
|
|
1042
|
+
if (asObject(dict.result) !== void 0) {
|
|
965
1043
|
return { kind: "match", match: parseStreamCallbackMatch(dict.result) };
|
|
966
1044
|
}
|
|
967
1045
|
return { kind: "keepalive" };
|
|
@@ -1040,6 +1118,7 @@ function startLongpoll(cfg) {
|
|
|
1040
1118
|
|
|
1041
1119
|
// src/streams.ts
|
|
1042
1120
|
var API_BASE = "https://api.audd.io";
|
|
1121
|
+
var LONGPOLL_TIMEOUT_MARGIN_SEC = 10;
|
|
1043
1122
|
var NO_CALLBACK_ERROR_CODE = 19;
|
|
1044
1123
|
var PREFLIGHT_NO_CALLBACK_HINT = "Longpoll won't deliver events because no callback URL is configured for this account. Set one first via streams.setCallbackUrl(...) \u2014 `https://audd.tech/empty/` is fine if you only want longpolling and don't need a real receiver. To skip this check, pass skipCallbackCheck: true.";
|
|
1045
1124
|
function decodeSuccess(body, httpStatus, requestId) {
|
|
@@ -1064,34 +1143,26 @@ function decodeSuccess(body, httpStatus, requestId) {
|
|
|
1064
1143
|
rawResponse: obj
|
|
1065
1144
|
});
|
|
1066
1145
|
}
|
|
1067
|
-
async function runRetried(fn, policy) {
|
|
1068
|
-
try {
|
|
1069
|
-
return await retry(fn, policy);
|
|
1070
|
-
} catch (err) {
|
|
1071
|
-
if (err instanceof TypeError) {
|
|
1072
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1073
|
-
}
|
|
1074
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1075
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1076
|
-
}
|
|
1077
|
-
throw err;
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
1146
|
var Streams = class {
|
|
1081
|
-
constructor(http, readPolicy, mutatingPolicy, apiToken) {
|
|
1147
|
+
constructor(http, readPolicy, mutatingPolicy, apiToken, onEvent) {
|
|
1082
1148
|
this.http = http;
|
|
1083
1149
|
this.readPolicy = readPolicy;
|
|
1084
1150
|
this.mutatingPolicy = mutatingPolicy;
|
|
1085
1151
|
this.apiToken = apiToken;
|
|
1152
|
+
this.onEvent = onEvent;
|
|
1086
1153
|
}
|
|
1087
1154
|
http;
|
|
1088
1155
|
readPolicy;
|
|
1089
1156
|
mutatingPolicy;
|
|
1090
1157
|
apiToken;
|
|
1158
|
+
onEvent;
|
|
1091
1159
|
async post(path2, fields, policy) {
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1160
|
+
const url = `${API_BASE}/${path2}/`;
|
|
1161
|
+
const resp = await emitAround(
|
|
1162
|
+
this.onEvent,
|
|
1163
|
+
path2,
|
|
1164
|
+
url,
|
|
1165
|
+
() => runRetried(() => this.http.postForm(url, fields), policy)
|
|
1095
1166
|
);
|
|
1096
1167
|
return decodeSuccess(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1097
1168
|
}
|
|
@@ -1138,11 +1209,11 @@ var Streams = class {
|
|
|
1138
1209
|
async list() {
|
|
1139
1210
|
const result = await this.post("getStreams", {}, this.readPolicy);
|
|
1140
1211
|
if (!Array.isArray(result)) return [];
|
|
1141
|
-
return result.map(parseStream);
|
|
1212
|
+
return result.filter((x) => asObject(x) !== void 0).map(parseStream);
|
|
1142
1213
|
}
|
|
1143
1214
|
/** Compute the 9-char longpoll category locally — pure, no network. */
|
|
1144
1215
|
deriveLongpollCategory(radioId) {
|
|
1145
|
-
return deriveLongpollCategory(this.apiToken, radioId);
|
|
1216
|
+
return deriveLongpollCategory(this.apiToken(), radioId);
|
|
1146
1217
|
}
|
|
1147
1218
|
/**
|
|
1148
1219
|
* Parse a callback POST body into `{ match, notification }`. Pass an
|
|
@@ -1184,13 +1255,21 @@ var Streams = class {
|
|
|
1184
1255
|
const timeoutSec = effectiveOpts.timeout ?? 50;
|
|
1185
1256
|
const httpClient = this.http;
|
|
1186
1257
|
const readPolicy = this.readPolicy;
|
|
1258
|
+
const onEvent = this.onEvent;
|
|
1259
|
+
const longpollUrl = `${API_BASE}/longpoll/`;
|
|
1260
|
+
const timeoutMs = (timeoutSec + LONGPOLL_TIMEOUT_MARGIN_SEC) * 1e3;
|
|
1187
1261
|
return startLongpoll({
|
|
1188
1262
|
category,
|
|
1189
1263
|
timeout: timeoutSec,
|
|
1190
1264
|
sinceTime: effectiveOpts.sinceTime,
|
|
1191
|
-
fetchOnce: (params, signal) =>
|
|
1192
|
-
|
|
1193
|
-
|
|
1265
|
+
fetchOnce: (params, signal) => emitAround(
|
|
1266
|
+
onEvent,
|
|
1267
|
+
"longpoll",
|
|
1268
|
+
longpollUrl,
|
|
1269
|
+
() => runRetried(
|
|
1270
|
+
() => httpClient.get(longpollUrl, params, { signal, timeoutMs }),
|
|
1271
|
+
readPolicy
|
|
1272
|
+
)
|
|
1194
1273
|
)
|
|
1195
1274
|
});
|
|
1196
1275
|
}
|
|
@@ -1235,26 +1314,15 @@ function decodeSuccess2(body, httpStatus, requestId) {
|
|
|
1235
1314
|
});
|
|
1236
1315
|
}
|
|
1237
1316
|
}
|
|
1238
|
-
async function runRetried2(fn, policy) {
|
|
1239
|
-
try {
|
|
1240
|
-
return await retry(fn, policy);
|
|
1241
|
-
} catch (err) {
|
|
1242
|
-
if (err instanceof TypeError) {
|
|
1243
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1244
|
-
}
|
|
1245
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1246
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1247
|
-
}
|
|
1248
|
-
throw err;
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
1317
|
var CustomCatalog = class {
|
|
1252
|
-
constructor(http, noRetryPolicy) {
|
|
1318
|
+
constructor(http, noRetryPolicy, onEvent) {
|
|
1253
1319
|
this.http = http;
|
|
1254
1320
|
this.noRetryPolicy = noRetryPolicy;
|
|
1321
|
+
this.onEvent = onEvent;
|
|
1255
1322
|
}
|
|
1256
1323
|
http;
|
|
1257
1324
|
noRetryPolicy;
|
|
1325
|
+
onEvent;
|
|
1258
1326
|
/**
|
|
1259
1327
|
* **This is NOT how you submit audio for music recognition.** For
|
|
1260
1328
|
* recognition, use `audd.recognize()` (or `audd.recognizeEnterprise()` for
|
|
@@ -1275,42 +1343,36 @@ var CustomCatalog = class {
|
|
|
1275
1343
|
async add(opts) {
|
|
1276
1344
|
const reopen = prepareSource(opts.source);
|
|
1277
1345
|
const audioId = String(opts.audioId);
|
|
1278
|
-
const resp = await
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1346
|
+
const resp = await emitAround(
|
|
1347
|
+
this.onEvent,
|
|
1348
|
+
"customCatalogAdd",
|
|
1349
|
+
UPLOAD_URL,
|
|
1350
|
+
() => runRetried(async () => {
|
|
1351
|
+
const prepared = await reopen();
|
|
1352
|
+
const fields = { ...prepared.fields, audio_id: audioId };
|
|
1353
|
+
return this.http.postForm(UPLOAD_URL, fields);
|
|
1354
|
+
}, this.noRetryPolicy)
|
|
1355
|
+
);
|
|
1283
1356
|
decodeSuccess2(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1284
1357
|
}
|
|
1285
1358
|
};
|
|
1286
1359
|
|
|
1287
1360
|
// src/advanced.ts
|
|
1288
1361
|
var API_BASE2 = "https://api.audd.io";
|
|
1289
|
-
async function runRetried3(fn, policy) {
|
|
1290
|
-
try {
|
|
1291
|
-
return await retry(fn, policy);
|
|
1292
|
-
} catch (err) {
|
|
1293
|
-
if (err instanceof TypeError) {
|
|
1294
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1295
|
-
}
|
|
1296
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1297
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1298
|
-
}
|
|
1299
|
-
throw err;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
1362
|
var Advanced = class {
|
|
1303
1363
|
/**
|
|
1304
1364
|
* @param recognitionPolicy The findLyrics endpoint is metered and shouldn't
|
|
1305
1365
|
* double-bill on post-upload read timeout: Advanced uses RECOGNITION retry
|
|
1306
1366
|
* policy, not READ.
|
|
1307
1367
|
*/
|
|
1308
|
-
constructor(http, recognitionPolicy) {
|
|
1368
|
+
constructor(http, recognitionPolicy, onEvent) {
|
|
1309
1369
|
this.http = http;
|
|
1310
1370
|
this.recognitionPolicy = recognitionPolicy;
|
|
1371
|
+
this.onEvent = onEvent;
|
|
1311
1372
|
}
|
|
1312
1373
|
http;
|
|
1313
1374
|
recognitionPolicy;
|
|
1375
|
+
onEvent;
|
|
1314
1376
|
/** Find lyrics by free-text query. Returns a list of matches (possibly empty). */
|
|
1315
1377
|
async findLyrics(query) {
|
|
1316
1378
|
const body = await this.rawRequest("findLyrics", { q: query });
|
|
@@ -1334,9 +1396,12 @@ var Advanced = class {
|
|
|
1334
1396
|
if (v === void 0) continue;
|
|
1335
1397
|
fields[k] = String(v);
|
|
1336
1398
|
}
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
this.
|
|
1399
|
+
const url = `${API_BASE2}/${method}/`;
|
|
1400
|
+
const resp = await emitAround(
|
|
1401
|
+
this.onEvent,
|
|
1402
|
+
method,
|
|
1403
|
+
url,
|
|
1404
|
+
() => runRetried(() => this.http.postForm(url, fields), this.recognitionPolicy)
|
|
1340
1405
|
);
|
|
1341
1406
|
const body = resp.jsonBody;
|
|
1342
1407
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
@@ -1352,13 +1417,6 @@ var ENTERPRISE_BASE = "https://enterprise.audd.io";
|
|
|
1352
1417
|
var DEPRECATED_PARAMS_CODE = 51;
|
|
1353
1418
|
var HTTP_CLIENT_ERROR_FLOOR2 = 400;
|
|
1354
1419
|
var TOKEN_ENV_VAR = "AUDD_API_TOKEN";
|
|
1355
|
-
function safeEmit(hook, event) {
|
|
1356
|
-
if (hook === void 0) return;
|
|
1357
|
-
try {
|
|
1358
|
-
hook(event);
|
|
1359
|
-
} catch {
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
1420
|
function resolveToken(apiToken) {
|
|
1363
1421
|
if (apiToken !== void 0 && apiToken !== "") return apiToken;
|
|
1364
1422
|
const env = (typeof process !== "undefined" ? process.env[TOKEN_ENV_VAR] : void 0) ?? "";
|
|
@@ -1431,7 +1489,7 @@ function decodeOrRaise(resp) {
|
|
|
1431
1489
|
function decodeRecognize(resp) {
|
|
1432
1490
|
const body = decodeOrRaise(resp);
|
|
1433
1491
|
const result = body["result"];
|
|
1434
|
-
if (result
|
|
1492
|
+
if (asObject(result) === void 0) return null;
|
|
1435
1493
|
return parseRecognitionResult(result);
|
|
1436
1494
|
}
|
|
1437
1495
|
function decodeEnterprise(resp) {
|
|
@@ -1440,24 +1498,12 @@ function decodeEnterprise(resp) {
|
|
|
1440
1498
|
if (!Array.isArray(chunks)) return [];
|
|
1441
1499
|
const out = [];
|
|
1442
1500
|
for (const c of chunks) {
|
|
1501
|
+
if (asObject(c) === void 0) continue;
|
|
1443
1502
|
const chunk = parseEnterpriseChunkResult(c);
|
|
1444
1503
|
out.push(...chunk.songs);
|
|
1445
1504
|
}
|
|
1446
1505
|
return out;
|
|
1447
1506
|
}
|
|
1448
|
-
async function runRetried4(fn, policy) {
|
|
1449
|
-
try {
|
|
1450
|
-
return await retry(fn, policy);
|
|
1451
|
-
} catch (err) {
|
|
1452
|
-
if (err instanceof TypeError) {
|
|
1453
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1454
|
-
}
|
|
1455
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1456
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1457
|
-
}
|
|
1458
|
-
throw err;
|
|
1459
|
-
}
|
|
1460
|
-
}
|
|
1461
1507
|
var AudD = class {
|
|
1462
1508
|
_http;
|
|
1463
1509
|
_enterpriseHttp;
|
|
@@ -1515,7 +1561,8 @@ var AudD = class {
|
|
|
1515
1561
|
this._http,
|
|
1516
1562
|
this.policyFor("read"),
|
|
1517
1563
|
this.policyFor("mutating"),
|
|
1518
|
-
this._apiToken
|
|
1564
|
+
() => this._apiToken,
|
|
1565
|
+
this._onEvent
|
|
1519
1566
|
);
|
|
1520
1567
|
}
|
|
1521
1568
|
return this._streams;
|
|
@@ -1523,14 +1570,14 @@ var AudD = class {
|
|
|
1523
1570
|
/** Sub-namespace for the private fingerprint catalog. NOT for recognition. */
|
|
1524
1571
|
get customCatalog() {
|
|
1525
1572
|
if (this._customCatalog === void 0) {
|
|
1526
|
-
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"));
|
|
1573
|
+
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"), this._onEvent);
|
|
1527
1574
|
}
|
|
1528
1575
|
return this._customCatalog;
|
|
1529
1576
|
}
|
|
1530
1577
|
/** Lyrics search + raw-request escape hatch. */
|
|
1531
1578
|
get advanced() {
|
|
1532
1579
|
if (this._advanced === void 0) {
|
|
1533
|
-
this._advanced = new Advanced(this._http, this.policyFor("recognition"));
|
|
1580
|
+
this._advanced = new Advanced(this._http, this.policyFor("recognition"), this._onEvent);
|
|
1534
1581
|
}
|
|
1535
1582
|
return this._advanced;
|
|
1536
1583
|
}
|
|
@@ -1546,20 +1593,11 @@ var AudD = class {
|
|
|
1546
1593
|
const market = opts.market;
|
|
1547
1594
|
const policy = this.policyFor("recognition");
|
|
1548
1595
|
const url = `${API_BASE3}/`;
|
|
1549
|
-
const
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
method: "recognize",
|
|
1596
|
+
const resp = await emitAround(
|
|
1597
|
+
this._onEvent,
|
|
1598
|
+
"recognize",
|
|
1553
1599
|
url,
|
|
1554
|
-
|
|
1555
|
-
httpStatus: null,
|
|
1556
|
-
elapsedMs: null,
|
|
1557
|
-
errorCode: null,
|
|
1558
|
-
extras: {}
|
|
1559
|
-
});
|
|
1560
|
-
let resp;
|
|
1561
|
-
try {
|
|
1562
|
-
resp = await runRetried4(async () => {
|
|
1600
|
+
() => runRetried(async () => {
|
|
1563
1601
|
const prepared = await reopen();
|
|
1564
1602
|
const fields = { ...prepared.fields };
|
|
1565
1603
|
if (opts.extraParameters) Object.assign(fields, opts.extraParameters);
|
|
@@ -1569,30 +1607,8 @@ var AudD = class {
|
|
|
1569
1607
|
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1570
1608
|
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1571
1609
|
});
|
|
1572
|
-
}, policy)
|
|
1573
|
-
|
|
1574
|
-
safeEmit(this._onEvent, {
|
|
1575
|
-
kind: "exception",
|
|
1576
|
-
method: "recognize",
|
|
1577
|
-
url,
|
|
1578
|
-
requestId: null,
|
|
1579
|
-
httpStatus: null,
|
|
1580
|
-
elapsedMs: Date.now() - startedAt,
|
|
1581
|
-
errorCode: null,
|
|
1582
|
-
extras: { name: err instanceof Error ? err.name : String(err) }
|
|
1583
|
-
});
|
|
1584
|
-
throw err;
|
|
1585
|
-
}
|
|
1586
|
-
safeEmit(this._onEvent, {
|
|
1587
|
-
kind: "response",
|
|
1588
|
-
method: "recognize",
|
|
1589
|
-
url,
|
|
1590
|
-
requestId: resp.requestId,
|
|
1591
|
-
httpStatus: resp.httpStatus,
|
|
1592
|
-
elapsedMs: Date.now() - startedAt,
|
|
1593
|
-
errorCode: null,
|
|
1594
|
-
extras: {}
|
|
1595
|
-
});
|
|
1610
|
+
}, policy)
|
|
1611
|
+
);
|
|
1596
1612
|
return decodeRecognize(resp);
|
|
1597
1613
|
}
|
|
1598
1614
|
/**
|
|
@@ -1605,14 +1621,20 @@ var AudD = class {
|
|
|
1605
1621
|
const reopen = prepareSource(source);
|
|
1606
1622
|
const extra = buildEnterpriseFields(opts);
|
|
1607
1623
|
const policy = this.policyFor("recognition");
|
|
1608
|
-
const
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1624
|
+
const url = `${ENTERPRISE_BASE}/`;
|
|
1625
|
+
const resp = await emitAround(
|
|
1626
|
+
this._onEvent,
|
|
1627
|
+
"recognizeEnterprise",
|
|
1628
|
+
url,
|
|
1629
|
+
() => runRetried(async () => {
|
|
1630
|
+
const prepared = await reopen();
|
|
1631
|
+
const fields = { ...prepared.fields, ...extra };
|
|
1632
|
+
return this._enterpriseHttp.postForm(url, fields, {
|
|
1633
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1634
|
+
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1635
|
+
});
|
|
1636
|
+
}, policy)
|
|
1637
|
+
);
|
|
1616
1638
|
return decodeEnterprise(resp);
|
|
1617
1639
|
}
|
|
1618
1640
|
/** Release any underlying resources. (Currently a no-op for `fetch`-based transport.) */
|