@audd/sdk 1.5.10 → 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 +18 -12
- package/dist/index.cjs +196 -147
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -27
- package/dist/index.d.ts +37 -27
- package/dist/index.js +196 -147
- 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-BRyps2P4.d.cts → longpollCore-BXx8PRmC.d.cts} +8 -5
- package/dist/{longpollCore-BRyps2P4.d.ts → longpollCore-BXx8PRmC.d.ts} +8 -5
- package/package.json +19 -10
package/dist/index.cjs
CHANGED
|
@@ -25,7 +25,7 @@ function _interopNamespace(e) {
|
|
|
25
25
|
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
26
26
|
|
|
27
27
|
// src/version.ts
|
|
28
|
-
var VERSION = "1.5.
|
|
28
|
+
var VERSION = "1.5.12";
|
|
29
29
|
|
|
30
30
|
// src/errors.ts
|
|
31
31
|
var AudDError = class extends Error {
|
|
@@ -98,6 +98,16 @@ var AudDConnectionError = class extends AudDError {
|
|
|
98
98
|
this.cause = cause;
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
|
+
var USER_ABORT_ERROR_NAME = "UserAbortError";
|
|
102
|
+
function userAbortError(cause) {
|
|
103
|
+
const err = new Error("Request was cancelled by the caller's AbortSignal");
|
|
104
|
+
err.name = USER_ABORT_ERROR_NAME;
|
|
105
|
+
err.cause = cause;
|
|
106
|
+
return err;
|
|
107
|
+
}
|
|
108
|
+
function isUserAbortError(err) {
|
|
109
|
+
return err !== null && typeof err === "object" && err.name === USER_ABORT_ERROR_NAME;
|
|
110
|
+
}
|
|
101
111
|
var AudDSerializationError = class extends AudDError {
|
|
102
112
|
name = "AudDSerializationError";
|
|
103
113
|
rawText;
|
|
@@ -170,6 +180,55 @@ function raiseFromErrorResponse(body, opts) {
|
|
|
170
180
|
throw new Cls(fields);
|
|
171
181
|
}
|
|
172
182
|
|
|
183
|
+
// src/events.ts
|
|
184
|
+
function safeEmit(hook, event) {
|
|
185
|
+
if (hook === void 0) return;
|
|
186
|
+
try {
|
|
187
|
+
hook(event);
|
|
188
|
+
} catch {
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async function emitAround(hook, method, url, fn) {
|
|
192
|
+
const startedAt = Date.now();
|
|
193
|
+
safeEmit(hook, {
|
|
194
|
+
kind: "request",
|
|
195
|
+
method,
|
|
196
|
+
url,
|
|
197
|
+
requestId: null,
|
|
198
|
+
httpStatus: null,
|
|
199
|
+
elapsedMs: null,
|
|
200
|
+
errorCode: null,
|
|
201
|
+
extras: {}
|
|
202
|
+
});
|
|
203
|
+
let resp;
|
|
204
|
+
try {
|
|
205
|
+
resp = await fn();
|
|
206
|
+
} catch (err) {
|
|
207
|
+
safeEmit(hook, {
|
|
208
|
+
kind: "exception",
|
|
209
|
+
method,
|
|
210
|
+
url,
|
|
211
|
+
requestId: null,
|
|
212
|
+
httpStatus: null,
|
|
213
|
+
elapsedMs: Date.now() - startedAt,
|
|
214
|
+
errorCode: null,
|
|
215
|
+
extras: { name: err instanceof Error ? err.name : String(err) }
|
|
216
|
+
});
|
|
217
|
+
throw err;
|
|
218
|
+
}
|
|
219
|
+
safeEmit(hook, {
|
|
220
|
+
kind: "response",
|
|
221
|
+
method,
|
|
222
|
+
url,
|
|
223
|
+
requestId: resp.requestId,
|
|
224
|
+
httpStatus: resp.httpStatus,
|
|
225
|
+
elapsedMs: Date.now() - startedAt,
|
|
226
|
+
errorCode: null,
|
|
227
|
+
extras: {}
|
|
228
|
+
});
|
|
229
|
+
return resp;
|
|
230
|
+
}
|
|
231
|
+
|
|
173
232
|
// src/userAgent.ts
|
|
174
233
|
function userAgent() {
|
|
175
234
|
const node = typeof process !== "undefined" && process.version ? process.version.replace(/^v/, "") : "unknown";
|
|
@@ -247,6 +306,11 @@ var HttpClient = class {
|
|
|
247
306
|
requestId: response.headers.get("x-request-id"),
|
|
248
307
|
rawText: text
|
|
249
308
|
};
|
|
309
|
+
} catch (err) {
|
|
310
|
+
if (userSignal?.aborted === true && err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
311
|
+
throw userAbortError(err);
|
|
312
|
+
}
|
|
313
|
+
throw err;
|
|
250
314
|
} finally {
|
|
251
315
|
clearTimeout(timer);
|
|
252
316
|
if (userSignal !== void 0) {
|
|
@@ -271,10 +335,8 @@ function asObject(raw) {
|
|
|
271
335
|
}
|
|
272
336
|
return void 0;
|
|
273
337
|
}
|
|
274
|
-
function
|
|
275
|
-
|
|
276
|
-
if (o === void 0) throw new TypeError(`${what}: expected object`);
|
|
277
|
-
return o;
|
|
338
|
+
function asObjectLenient(raw) {
|
|
339
|
+
return asObject(raw) ?? {};
|
|
278
340
|
}
|
|
279
341
|
function asString(v) {
|
|
280
342
|
return typeof v === "string" ? v : void 0;
|
|
@@ -285,6 +347,20 @@ function asNumber(v) {
|
|
|
285
347
|
function asBoolean(v) {
|
|
286
348
|
return typeof v === "boolean" ? v : void 0;
|
|
287
349
|
}
|
|
350
|
+
function parseOffsetToSeconds(o) {
|
|
351
|
+
if (o === void 0 || o === null) return void 0;
|
|
352
|
+
if (typeof o === "number") return Number.isFinite(o) ? o : void 0;
|
|
353
|
+
const t = String(o).trim();
|
|
354
|
+
if (t === "") return void 0;
|
|
355
|
+
let total = 0;
|
|
356
|
+
for (const part of t.split(":")) {
|
|
357
|
+
if (part.trim() === "") return void 0;
|
|
358
|
+
const n = Number(part);
|
|
359
|
+
if (!Number.isFinite(n)) return void 0;
|
|
360
|
+
total = total * 60 + n;
|
|
361
|
+
}
|
|
362
|
+
return total;
|
|
363
|
+
}
|
|
288
364
|
var STREAMING_PROVIDERS = [
|
|
289
365
|
"spotify",
|
|
290
366
|
"apple_music",
|
|
@@ -364,7 +440,7 @@ var RECOGNITION_KEYS = [
|
|
|
364
440
|
"musicbrainz"
|
|
365
441
|
];
|
|
366
442
|
function parseRecognitionResult(raw) {
|
|
367
|
-
const r =
|
|
443
|
+
const r = asObjectLenient(raw);
|
|
368
444
|
const timecode = asString(r.timecode);
|
|
369
445
|
const audioId = asNumber(r.audio_id);
|
|
370
446
|
const artist = asString(r.artist);
|
|
@@ -434,10 +510,12 @@ var ENTERPRISE_MATCH_KEYS = [
|
|
|
434
510
|
"upc",
|
|
435
511
|
"song_link",
|
|
436
512
|
"start_offset",
|
|
437
|
-
"end_offset"
|
|
513
|
+
"end_offset",
|
|
514
|
+
"start_seconds",
|
|
515
|
+
"end_seconds"
|
|
438
516
|
];
|
|
439
517
|
function parseEnterpriseMatch(raw) {
|
|
440
|
-
const r =
|
|
518
|
+
const r = asObjectLenient(raw);
|
|
441
519
|
const score = asNumber(r.score);
|
|
442
520
|
const timecode = asString(r.timecode);
|
|
443
521
|
const songLink = asString(r.song_link);
|
|
@@ -454,6 +532,8 @@ function parseEnterpriseMatch(raw) {
|
|
|
454
532
|
songLink,
|
|
455
533
|
startOffset: asNumber(r.start_offset),
|
|
456
534
|
endOffset: asNumber(r.end_offset),
|
|
535
|
+
startSeconds: void 0,
|
|
536
|
+
endSeconds: void 0,
|
|
457
537
|
extras: pickExtras(r, ENTERPRISE_MATCH_KEYS),
|
|
458
538
|
rawResponse: r,
|
|
459
539
|
streamingUrl(provider) {
|
|
@@ -485,11 +565,20 @@ function parseEnterpriseMatch(raw) {
|
|
|
485
565
|
}
|
|
486
566
|
var ENTERPRISE_CHUNK_KEYS = ["songs", "offset"];
|
|
487
567
|
function parseEnterpriseChunkResult(raw) {
|
|
488
|
-
const r =
|
|
489
|
-
const songsRaw = Array.isArray(r.songs) ? r.songs : [];
|
|
568
|
+
const r = asObjectLenient(raw);
|
|
569
|
+
const songsRaw = Array.isArray(r.songs) ? r.songs.filter((s) => asObject(s) !== void 0) : [];
|
|
490
570
|
const offset = asString(r.offset);
|
|
571
|
+
const base = parseOffsetToSeconds(r.offset);
|
|
572
|
+
const songs = songsRaw.map((s) => {
|
|
573
|
+
const match = parseEnterpriseMatch(s);
|
|
574
|
+
if (base !== void 0) {
|
|
575
|
+
match.startSeconds = base + (match.startOffset ?? 0) / 1e3;
|
|
576
|
+
match.endSeconds = base + (match.endOffset ?? 0) / 1e3;
|
|
577
|
+
}
|
|
578
|
+
return match;
|
|
579
|
+
});
|
|
491
580
|
return {
|
|
492
|
-
songs
|
|
581
|
+
songs,
|
|
493
582
|
offset,
|
|
494
583
|
extras: pickExtras(r, ENTERPRISE_CHUNK_KEYS),
|
|
495
584
|
rawResponse: r
|
|
@@ -497,7 +586,7 @@ function parseEnterpriseChunkResult(raw) {
|
|
|
497
586
|
}
|
|
498
587
|
var STREAM_KEYS = ["radio_id", "url", "stream_running", "longpoll_category"];
|
|
499
588
|
function parseStream(raw) {
|
|
500
|
-
const r =
|
|
589
|
+
const r = asObjectLenient(raw);
|
|
501
590
|
const radioId = asNumber(r.radio_id);
|
|
502
591
|
const url = asString(r.url);
|
|
503
592
|
const streamRunning = asBoolean(r.stream_running);
|
|
@@ -527,7 +616,7 @@ var STREAM_CALLBACK_SONG_KEYS = [
|
|
|
527
616
|
"musicbrainz"
|
|
528
617
|
];
|
|
529
618
|
function parseStreamCallbackSong(raw) {
|
|
530
|
-
const r =
|
|
619
|
+
const r = asObjectLenient(raw);
|
|
531
620
|
const artist = asString(r.artist);
|
|
532
621
|
const title = asString(r.title);
|
|
533
622
|
const score = asNumber(r.score);
|
|
@@ -557,7 +646,7 @@ var STREAM_CALLBACK_MATCH_KEYS = [
|
|
|
557
646
|
"results"
|
|
558
647
|
];
|
|
559
648
|
function parseStreamCallbackMatch(raw) {
|
|
560
|
-
const r =
|
|
649
|
+
const r = asObjectLenient(raw);
|
|
561
650
|
const radioId = asNumber(r.radio_id);
|
|
562
651
|
const resultsRaw = Array.isArray(r.results) ? r.results : [];
|
|
563
652
|
const songs = resultsRaw.filter((x) => asObject(x) !== void 0).map(parseStreamCallbackSong);
|
|
@@ -579,7 +668,7 @@ var STREAM_CALLBACK_NOTIFICATION_KEYS = [
|
|
|
579
668
|
"notification_message"
|
|
580
669
|
];
|
|
581
670
|
function parseStreamCallbackNotification(raw) {
|
|
582
|
-
const r =
|
|
671
|
+
const r = asObjectLenient(raw);
|
|
583
672
|
const radioId = asNumber(r.radio_id);
|
|
584
673
|
const code = asNumber(r.notification_code);
|
|
585
674
|
const message = asString(r.notification_message);
|
|
@@ -603,7 +692,7 @@ var LYRICS_KEYS = [
|
|
|
603
692
|
"media"
|
|
604
693
|
];
|
|
605
694
|
function parseLyricsResult(raw) {
|
|
606
|
-
const r =
|
|
695
|
+
const r = asObjectLenient(raw);
|
|
607
696
|
const artist = asString(r.artist);
|
|
608
697
|
const title = asString(r.title);
|
|
609
698
|
return {
|
|
@@ -699,6 +788,22 @@ async function retry(fn, policy) {
|
|
|
699
788
|
if (haveResp && lastResp !== void 0) return lastResp;
|
|
700
789
|
throw lastError;
|
|
701
790
|
}
|
|
791
|
+
async function runRetried(fn, policy) {
|
|
792
|
+
try {
|
|
793
|
+
return await retry(fn, policy);
|
|
794
|
+
} catch (err) {
|
|
795
|
+
if (isUserAbortError(err)) {
|
|
796
|
+
throw new AudDConnectionError("Request was cancelled by the caller's AbortSignal", err);
|
|
797
|
+
}
|
|
798
|
+
if (err instanceof TypeError) {
|
|
799
|
+
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
800
|
+
}
|
|
801
|
+
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
802
|
+
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
803
|
+
}
|
|
804
|
+
throw err;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
702
807
|
function looksLikeUrl(s) {
|
|
703
808
|
return s.startsWith("http://") || s.startsWith("https://");
|
|
704
809
|
}
|
|
@@ -950,13 +1055,13 @@ function decodeOne(resp) {
|
|
|
950
1055
|
);
|
|
951
1056
|
}
|
|
952
1057
|
const dict = body;
|
|
953
|
-
if (
|
|
1058
|
+
if (asObject(dict.notification) !== void 0) {
|
|
954
1059
|
const notification = parseStreamCallbackNotification(dict.notification);
|
|
955
1060
|
const t = dict["time"];
|
|
956
1061
|
if (typeof t === "number") notification.time = t;
|
|
957
1062
|
return { kind: "notification", notification };
|
|
958
1063
|
}
|
|
959
|
-
if (
|
|
1064
|
+
if (asObject(dict.result) !== void 0) {
|
|
960
1065
|
return { kind: "match", match: parseStreamCallbackMatch(dict.result) };
|
|
961
1066
|
}
|
|
962
1067
|
return { kind: "keepalive" };
|
|
@@ -1035,6 +1140,7 @@ function startLongpoll(cfg) {
|
|
|
1035
1140
|
|
|
1036
1141
|
// src/streams.ts
|
|
1037
1142
|
var API_BASE = "https://api.audd.io";
|
|
1143
|
+
var LONGPOLL_TIMEOUT_MARGIN_SEC = 10;
|
|
1038
1144
|
var NO_CALLBACK_ERROR_CODE = 19;
|
|
1039
1145
|
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.";
|
|
1040
1146
|
function decodeSuccess(body, httpStatus, requestId) {
|
|
@@ -1059,34 +1165,26 @@ function decodeSuccess(body, httpStatus, requestId) {
|
|
|
1059
1165
|
rawResponse: obj
|
|
1060
1166
|
});
|
|
1061
1167
|
}
|
|
1062
|
-
async function runRetried(fn, policy) {
|
|
1063
|
-
try {
|
|
1064
|
-
return await retry(fn, policy);
|
|
1065
|
-
} catch (err) {
|
|
1066
|
-
if (err instanceof TypeError) {
|
|
1067
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1068
|
-
}
|
|
1069
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1070
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1071
|
-
}
|
|
1072
|
-
throw err;
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
1168
|
var Streams = class {
|
|
1076
|
-
constructor(http, readPolicy, mutatingPolicy, apiToken) {
|
|
1169
|
+
constructor(http, readPolicy, mutatingPolicy, apiToken, onEvent) {
|
|
1077
1170
|
this.http = http;
|
|
1078
1171
|
this.readPolicy = readPolicy;
|
|
1079
1172
|
this.mutatingPolicy = mutatingPolicy;
|
|
1080
1173
|
this.apiToken = apiToken;
|
|
1174
|
+
this.onEvent = onEvent;
|
|
1081
1175
|
}
|
|
1082
1176
|
http;
|
|
1083
1177
|
readPolicy;
|
|
1084
1178
|
mutatingPolicy;
|
|
1085
1179
|
apiToken;
|
|
1180
|
+
onEvent;
|
|
1086
1181
|
async post(path2, fields, policy) {
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
|
|
1182
|
+
const url = `${API_BASE}/${path2}/`;
|
|
1183
|
+
const resp = await emitAround(
|
|
1184
|
+
this.onEvent,
|
|
1185
|
+
path2,
|
|
1186
|
+
url,
|
|
1187
|
+
() => runRetried(() => this.http.postForm(url, fields), policy)
|
|
1090
1188
|
);
|
|
1091
1189
|
return decodeSuccess(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1092
1190
|
}
|
|
@@ -1133,11 +1231,11 @@ var Streams = class {
|
|
|
1133
1231
|
async list() {
|
|
1134
1232
|
const result = await this.post("getStreams", {}, this.readPolicy);
|
|
1135
1233
|
if (!Array.isArray(result)) return [];
|
|
1136
|
-
return result.map(parseStream);
|
|
1234
|
+
return result.filter((x) => asObject(x) !== void 0).map(parseStream);
|
|
1137
1235
|
}
|
|
1138
1236
|
/** Compute the 9-char longpoll category locally — pure, no network. */
|
|
1139
1237
|
deriveLongpollCategory(radioId) {
|
|
1140
|
-
return deriveLongpollCategory(this.apiToken, radioId);
|
|
1238
|
+
return deriveLongpollCategory(this.apiToken(), radioId);
|
|
1141
1239
|
}
|
|
1142
1240
|
/**
|
|
1143
1241
|
* Parse a callback POST body into `{ match, notification }`. Pass an
|
|
@@ -1179,13 +1277,21 @@ var Streams = class {
|
|
|
1179
1277
|
const timeoutSec = effectiveOpts.timeout ?? 50;
|
|
1180
1278
|
const httpClient = this.http;
|
|
1181
1279
|
const readPolicy = this.readPolicy;
|
|
1280
|
+
const onEvent = this.onEvent;
|
|
1281
|
+
const longpollUrl = `${API_BASE}/longpoll/`;
|
|
1282
|
+
const timeoutMs = (timeoutSec + LONGPOLL_TIMEOUT_MARGIN_SEC) * 1e3;
|
|
1182
1283
|
return startLongpoll({
|
|
1183
1284
|
category,
|
|
1184
1285
|
timeout: timeoutSec,
|
|
1185
1286
|
sinceTime: effectiveOpts.sinceTime,
|
|
1186
|
-
fetchOnce: (params, signal) =>
|
|
1187
|
-
|
|
1188
|
-
|
|
1287
|
+
fetchOnce: (params, signal) => emitAround(
|
|
1288
|
+
onEvent,
|
|
1289
|
+
"longpoll",
|
|
1290
|
+
longpollUrl,
|
|
1291
|
+
() => runRetried(
|
|
1292
|
+
() => httpClient.get(longpollUrl, params, { signal, timeoutMs }),
|
|
1293
|
+
readPolicy
|
|
1294
|
+
)
|
|
1189
1295
|
)
|
|
1190
1296
|
});
|
|
1191
1297
|
}
|
|
@@ -1230,26 +1336,15 @@ function decodeSuccess2(body, httpStatus, requestId) {
|
|
|
1230
1336
|
});
|
|
1231
1337
|
}
|
|
1232
1338
|
}
|
|
1233
|
-
async function runRetried2(fn, policy) {
|
|
1234
|
-
try {
|
|
1235
|
-
return await retry(fn, policy);
|
|
1236
|
-
} catch (err) {
|
|
1237
|
-
if (err instanceof TypeError) {
|
|
1238
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1239
|
-
}
|
|
1240
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1241
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1242
|
-
}
|
|
1243
|
-
throw err;
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
1246
1339
|
var CustomCatalog = class {
|
|
1247
|
-
constructor(http, noRetryPolicy) {
|
|
1340
|
+
constructor(http, noRetryPolicy, onEvent) {
|
|
1248
1341
|
this.http = http;
|
|
1249
1342
|
this.noRetryPolicy = noRetryPolicy;
|
|
1343
|
+
this.onEvent = onEvent;
|
|
1250
1344
|
}
|
|
1251
1345
|
http;
|
|
1252
1346
|
noRetryPolicy;
|
|
1347
|
+
onEvent;
|
|
1253
1348
|
/**
|
|
1254
1349
|
* **This is NOT how you submit audio for music recognition.** For
|
|
1255
1350
|
* recognition, use `audd.recognize()` (or `audd.recognizeEnterprise()` for
|
|
@@ -1270,42 +1365,36 @@ var CustomCatalog = class {
|
|
|
1270
1365
|
async add(opts) {
|
|
1271
1366
|
const reopen = prepareSource(opts.source);
|
|
1272
1367
|
const audioId = String(opts.audioId);
|
|
1273
|
-
const resp = await
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1368
|
+
const resp = await emitAround(
|
|
1369
|
+
this.onEvent,
|
|
1370
|
+
"customCatalogAdd",
|
|
1371
|
+
UPLOAD_URL,
|
|
1372
|
+
() => runRetried(async () => {
|
|
1373
|
+
const prepared = await reopen();
|
|
1374
|
+
const fields = { ...prepared.fields, audio_id: audioId };
|
|
1375
|
+
return this.http.postForm(UPLOAD_URL, fields);
|
|
1376
|
+
}, this.noRetryPolicy)
|
|
1377
|
+
);
|
|
1278
1378
|
decodeSuccess2(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1279
1379
|
}
|
|
1280
1380
|
};
|
|
1281
1381
|
|
|
1282
1382
|
// src/advanced.ts
|
|
1283
1383
|
var API_BASE2 = "https://api.audd.io";
|
|
1284
|
-
async function runRetried3(fn, policy) {
|
|
1285
|
-
try {
|
|
1286
|
-
return await retry(fn, policy);
|
|
1287
|
-
} catch (err) {
|
|
1288
|
-
if (err instanceof TypeError) {
|
|
1289
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1290
|
-
}
|
|
1291
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1292
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1293
|
-
}
|
|
1294
|
-
throw err;
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
1384
|
var Advanced = class {
|
|
1298
1385
|
/**
|
|
1299
1386
|
* @param recognitionPolicy The findLyrics endpoint is metered and shouldn't
|
|
1300
1387
|
* double-bill on post-upload read timeout: Advanced uses RECOGNITION retry
|
|
1301
1388
|
* policy, not READ.
|
|
1302
1389
|
*/
|
|
1303
|
-
constructor(http, recognitionPolicy) {
|
|
1390
|
+
constructor(http, recognitionPolicy, onEvent) {
|
|
1304
1391
|
this.http = http;
|
|
1305
1392
|
this.recognitionPolicy = recognitionPolicy;
|
|
1393
|
+
this.onEvent = onEvent;
|
|
1306
1394
|
}
|
|
1307
1395
|
http;
|
|
1308
1396
|
recognitionPolicy;
|
|
1397
|
+
onEvent;
|
|
1309
1398
|
/** Find lyrics by free-text query. Returns a list of matches (possibly empty). */
|
|
1310
1399
|
async findLyrics(query) {
|
|
1311
1400
|
const body = await this.rawRequest("findLyrics", { q: query });
|
|
@@ -1329,9 +1418,12 @@ var Advanced = class {
|
|
|
1329
1418
|
if (v === void 0) continue;
|
|
1330
1419
|
fields[k] = String(v);
|
|
1331
1420
|
}
|
|
1332
|
-
const
|
|
1333
|
-
|
|
1334
|
-
this.
|
|
1421
|
+
const url = `${API_BASE2}/${method}/`;
|
|
1422
|
+
const resp = await emitAround(
|
|
1423
|
+
this.onEvent,
|
|
1424
|
+
method,
|
|
1425
|
+
url,
|
|
1426
|
+
() => runRetried(() => this.http.postForm(url, fields), this.recognitionPolicy)
|
|
1335
1427
|
);
|
|
1336
1428
|
const body = resp.jsonBody;
|
|
1337
1429
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
@@ -1347,13 +1439,6 @@ var ENTERPRISE_BASE = "https://enterprise.audd.io";
|
|
|
1347
1439
|
var DEPRECATED_PARAMS_CODE = 51;
|
|
1348
1440
|
var HTTP_CLIENT_ERROR_FLOOR2 = 400;
|
|
1349
1441
|
var TOKEN_ENV_VAR = "AUDD_API_TOKEN";
|
|
1350
|
-
function safeEmit(hook, event) {
|
|
1351
|
-
if (hook === void 0) return;
|
|
1352
|
-
try {
|
|
1353
|
-
hook(event);
|
|
1354
|
-
} catch {
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
1442
|
function resolveToken(apiToken) {
|
|
1358
1443
|
if (apiToken !== void 0 && apiToken !== "") return apiToken;
|
|
1359
1444
|
const env = (typeof process !== "undefined" ? process.env[TOKEN_ENV_VAR] : void 0) ?? "";
|
|
@@ -1376,8 +1461,8 @@ function buildEnterpriseFields(opts) {
|
|
|
1376
1461
|
if (opts.skipFirstSeconds !== void 0)
|
|
1377
1462
|
fields["skip_first_seconds"] = String(opts.skipFirstSeconds);
|
|
1378
1463
|
if (opts.useTimecode !== void 0) fields["use_timecode"] = opts.useTimecode ? "true" : "false";
|
|
1379
|
-
|
|
1380
|
-
|
|
1464
|
+
const accurate = opts.accurateOffsets ?? true;
|
|
1465
|
+
fields["accurate_offsets"] = accurate ? "true" : "false";
|
|
1381
1466
|
return fields;
|
|
1382
1467
|
}
|
|
1383
1468
|
function isDeprecationPassThrough(body) {
|
|
@@ -1426,7 +1511,7 @@ function decodeOrRaise(resp) {
|
|
|
1426
1511
|
function decodeRecognize(resp) {
|
|
1427
1512
|
const body = decodeOrRaise(resp);
|
|
1428
1513
|
const result = body["result"];
|
|
1429
|
-
if (result
|
|
1514
|
+
if (asObject(result) === void 0) return null;
|
|
1430
1515
|
return parseRecognitionResult(result);
|
|
1431
1516
|
}
|
|
1432
1517
|
function decodeEnterprise(resp) {
|
|
@@ -1435,24 +1520,12 @@ function decodeEnterprise(resp) {
|
|
|
1435
1520
|
if (!Array.isArray(chunks)) return [];
|
|
1436
1521
|
const out = [];
|
|
1437
1522
|
for (const c of chunks) {
|
|
1523
|
+
if (asObject(c) === void 0) continue;
|
|
1438
1524
|
const chunk = parseEnterpriseChunkResult(c);
|
|
1439
1525
|
out.push(...chunk.songs);
|
|
1440
1526
|
}
|
|
1441
1527
|
return out;
|
|
1442
1528
|
}
|
|
1443
|
-
async function runRetried4(fn, policy) {
|
|
1444
|
-
try {
|
|
1445
|
-
return await retry(fn, policy);
|
|
1446
|
-
} catch (err) {
|
|
1447
|
-
if (err instanceof TypeError) {
|
|
1448
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1449
|
-
}
|
|
1450
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1451
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1452
|
-
}
|
|
1453
|
-
throw err;
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
1529
|
var AudD = class {
|
|
1457
1530
|
_http;
|
|
1458
1531
|
_enterpriseHttp;
|
|
@@ -1510,7 +1583,8 @@ var AudD = class {
|
|
|
1510
1583
|
this._http,
|
|
1511
1584
|
this.policyFor("read"),
|
|
1512
1585
|
this.policyFor("mutating"),
|
|
1513
|
-
this._apiToken
|
|
1586
|
+
() => this._apiToken,
|
|
1587
|
+
this._onEvent
|
|
1514
1588
|
);
|
|
1515
1589
|
}
|
|
1516
1590
|
return this._streams;
|
|
@@ -1518,14 +1592,14 @@ var AudD = class {
|
|
|
1518
1592
|
/** Sub-namespace for the private fingerprint catalog. NOT for recognition. */
|
|
1519
1593
|
get customCatalog() {
|
|
1520
1594
|
if (this._customCatalog === void 0) {
|
|
1521
|
-
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"));
|
|
1595
|
+
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"), this._onEvent);
|
|
1522
1596
|
}
|
|
1523
1597
|
return this._customCatalog;
|
|
1524
1598
|
}
|
|
1525
1599
|
/** Lyrics search + raw-request escape hatch. */
|
|
1526
1600
|
get advanced() {
|
|
1527
1601
|
if (this._advanced === void 0) {
|
|
1528
|
-
this._advanced = new Advanced(this._http, this.policyFor("recognition"));
|
|
1602
|
+
this._advanced = new Advanced(this._http, this.policyFor("recognition"), this._onEvent);
|
|
1529
1603
|
}
|
|
1530
1604
|
return this._advanced;
|
|
1531
1605
|
}
|
|
@@ -1541,20 +1615,11 @@ var AudD = class {
|
|
|
1541
1615
|
const market = opts.market;
|
|
1542
1616
|
const policy = this.policyFor("recognition");
|
|
1543
1617
|
const url = `${API_BASE3}/`;
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
method: "recognize",
|
|
1618
|
+
const resp = await emitAround(
|
|
1619
|
+
this._onEvent,
|
|
1620
|
+
"recognize",
|
|
1548
1621
|
url,
|
|
1549
|
-
|
|
1550
|
-
httpStatus: null,
|
|
1551
|
-
elapsedMs: null,
|
|
1552
|
-
errorCode: null,
|
|
1553
|
-
extras: {}
|
|
1554
|
-
});
|
|
1555
|
-
let resp;
|
|
1556
|
-
try {
|
|
1557
|
-
resp = await runRetried4(async () => {
|
|
1622
|
+
() => runRetried(async () => {
|
|
1558
1623
|
const prepared = await reopen();
|
|
1559
1624
|
const fields = { ...prepared.fields };
|
|
1560
1625
|
if (opts.extraParameters) Object.assign(fields, opts.extraParameters);
|
|
@@ -1564,30 +1629,8 @@ var AudD = class {
|
|
|
1564
1629
|
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1565
1630
|
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1566
1631
|
});
|
|
1567
|
-
}, policy)
|
|
1568
|
-
|
|
1569
|
-
safeEmit(this._onEvent, {
|
|
1570
|
-
kind: "exception",
|
|
1571
|
-
method: "recognize",
|
|
1572
|
-
url,
|
|
1573
|
-
requestId: null,
|
|
1574
|
-
httpStatus: null,
|
|
1575
|
-
elapsedMs: Date.now() - startedAt,
|
|
1576
|
-
errorCode: null,
|
|
1577
|
-
extras: { name: err instanceof Error ? err.name : String(err) }
|
|
1578
|
-
});
|
|
1579
|
-
throw err;
|
|
1580
|
-
}
|
|
1581
|
-
safeEmit(this._onEvent, {
|
|
1582
|
-
kind: "response",
|
|
1583
|
-
method: "recognize",
|
|
1584
|
-
url,
|
|
1585
|
-
requestId: resp.requestId,
|
|
1586
|
-
httpStatus: resp.httpStatus,
|
|
1587
|
-
elapsedMs: Date.now() - startedAt,
|
|
1588
|
-
errorCode: null,
|
|
1589
|
-
extras: {}
|
|
1590
|
-
});
|
|
1632
|
+
}, policy)
|
|
1633
|
+
);
|
|
1591
1634
|
return decodeRecognize(resp);
|
|
1592
1635
|
}
|
|
1593
1636
|
/**
|
|
@@ -1600,14 +1643,20 @@ var AudD = class {
|
|
|
1600
1643
|
const reopen = prepareSource(source);
|
|
1601
1644
|
const extra = buildEnterpriseFields(opts);
|
|
1602
1645
|
const policy = this.policyFor("recognition");
|
|
1603
|
-
const
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1646
|
+
const url = `${ENTERPRISE_BASE}/`;
|
|
1647
|
+
const resp = await emitAround(
|
|
1648
|
+
this._onEvent,
|
|
1649
|
+
"recognizeEnterprise",
|
|
1650
|
+
url,
|
|
1651
|
+
() => runRetried(async () => {
|
|
1652
|
+
const prepared = await reopen();
|
|
1653
|
+
const fields = { ...prepared.fields, ...extra };
|
|
1654
|
+
return this._enterpriseHttp.postForm(url, fields, {
|
|
1655
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1656
|
+
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1657
|
+
});
|
|
1658
|
+
}, policy)
|
|
1659
|
+
);
|
|
1611
1660
|
return decodeEnterprise(resp);
|
|
1612
1661
|
}
|
|
1613
1662
|
/** Release any underlying resources. (Currently a no-op for `fetch`-based transport.) */
|