@audd/sdk 1.5.11 → 1.5.13
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 +203 -156
- 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 +203 -156
- package/dist/index.js.map +1 -1
- package/dist/longpoll.cjs +71 -25
- 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 +71 -25
- 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.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.13";
|
|
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,19 +335,42 @@ 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
|
+
if (typeof v === "string") return v;
|
|
343
|
+
if (typeof v === "number" || typeof v === "boolean") return String(v);
|
|
344
|
+
return void 0;
|
|
345
|
+
}
|
|
346
|
+
function toFiniteNumber(v) {
|
|
347
|
+
if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
|
|
348
|
+
if (typeof v === "boolean") return v ? 1 : 0;
|
|
349
|
+
if (typeof v === "string") {
|
|
350
|
+
const t = v.trim();
|
|
351
|
+
if (t === "") return void 0;
|
|
352
|
+
const n = Number(t);
|
|
353
|
+
return Number.isFinite(n) ? n : void 0;
|
|
354
|
+
}
|
|
355
|
+
return void 0;
|
|
281
356
|
}
|
|
282
357
|
function asNumber(v) {
|
|
283
|
-
return
|
|
358
|
+
return toFiniteNumber(v);
|
|
359
|
+
}
|
|
360
|
+
function asInteger(v) {
|
|
361
|
+
const n = toFiniteNumber(v);
|
|
362
|
+
return n === void 0 ? void 0 : Math.trunc(n);
|
|
284
363
|
}
|
|
285
364
|
function asBoolean(v) {
|
|
286
|
-
|
|
365
|
+
if (typeof v === "boolean") return v;
|
|
366
|
+
if (typeof v === "number") return v !== 0;
|
|
367
|
+
if (typeof v === "string") {
|
|
368
|
+
const t = v.trim().toLowerCase();
|
|
369
|
+
if (t === "true" || t === "1" || t === "yes" || t === "on") return true;
|
|
370
|
+
if (t === "false" || t === "0" || t === "no" || t === "off" || t === "") return false;
|
|
371
|
+
return void 0;
|
|
372
|
+
}
|
|
373
|
+
return void 0;
|
|
287
374
|
}
|
|
288
375
|
function parseOffsetToSeconds(o) {
|
|
289
376
|
if (o === void 0 || o === null) return void 0;
|
|
@@ -378,9 +465,9 @@ var RECOGNITION_KEYS = [
|
|
|
378
465
|
"musicbrainz"
|
|
379
466
|
];
|
|
380
467
|
function parseRecognitionResult(raw) {
|
|
381
|
-
const r =
|
|
468
|
+
const r = asObjectLenient(raw);
|
|
382
469
|
const timecode = asString(r.timecode);
|
|
383
|
-
const audioId =
|
|
470
|
+
const audioId = asInteger(r.audio_id);
|
|
384
471
|
const artist = asString(r.artist);
|
|
385
472
|
const title = asString(r.title);
|
|
386
473
|
const songLink = asString(r.song_link);
|
|
@@ -453,7 +540,7 @@ var ENTERPRISE_MATCH_KEYS = [
|
|
|
453
540
|
"end_seconds"
|
|
454
541
|
];
|
|
455
542
|
function parseEnterpriseMatch(raw) {
|
|
456
|
-
const r =
|
|
543
|
+
const r = asObjectLenient(raw);
|
|
457
544
|
const score = asNumber(r.score);
|
|
458
545
|
const timecode = asString(r.timecode);
|
|
459
546
|
const songLink = asString(r.song_link);
|
|
@@ -468,8 +555,8 @@ function parseEnterpriseMatch(raw) {
|
|
|
468
555
|
isrc: asString(r.isrc),
|
|
469
556
|
upc: asString(r.upc),
|
|
470
557
|
songLink,
|
|
471
|
-
startOffset:
|
|
472
|
-
endOffset:
|
|
558
|
+
startOffset: asInteger(r.start_offset),
|
|
559
|
+
endOffset: asInteger(r.end_offset),
|
|
473
560
|
startSeconds: void 0,
|
|
474
561
|
endSeconds: void 0,
|
|
475
562
|
extras: pickExtras(r, ENTERPRISE_MATCH_KEYS),
|
|
@@ -503,8 +590,8 @@ function parseEnterpriseMatch(raw) {
|
|
|
503
590
|
}
|
|
504
591
|
var ENTERPRISE_CHUNK_KEYS = ["songs", "offset"];
|
|
505
592
|
function parseEnterpriseChunkResult(raw) {
|
|
506
|
-
const r =
|
|
507
|
-
const songsRaw = Array.isArray(r.songs) ? r.songs : [];
|
|
593
|
+
const r = asObjectLenient(raw);
|
|
594
|
+
const songsRaw = Array.isArray(r.songs) ? r.songs.filter((s) => asObject(s) !== void 0) : [];
|
|
508
595
|
const offset = asString(r.offset);
|
|
509
596
|
const base = parseOffsetToSeconds(r.offset);
|
|
510
597
|
const songs = songsRaw.map((s) => {
|
|
@@ -524,8 +611,8 @@ function parseEnterpriseChunkResult(raw) {
|
|
|
524
611
|
}
|
|
525
612
|
var STREAM_KEYS = ["radio_id", "url", "stream_running", "longpoll_category"];
|
|
526
613
|
function parseStream(raw) {
|
|
527
|
-
const r =
|
|
528
|
-
const radioId =
|
|
614
|
+
const r = asObjectLenient(raw);
|
|
615
|
+
const radioId = asInteger(r.radio_id);
|
|
529
616
|
const url = asString(r.url);
|
|
530
617
|
const streamRunning = asBoolean(r.stream_running);
|
|
531
618
|
return {
|
|
@@ -554,7 +641,7 @@ var STREAM_CALLBACK_SONG_KEYS = [
|
|
|
554
641
|
"musicbrainz"
|
|
555
642
|
];
|
|
556
643
|
function parseStreamCallbackSong(raw) {
|
|
557
|
-
const r =
|
|
644
|
+
const r = asObjectLenient(raw);
|
|
558
645
|
const artist = asString(r.artist);
|
|
559
646
|
const title = asString(r.title);
|
|
560
647
|
const score = asNumber(r.score);
|
|
@@ -584,15 +671,15 @@ var STREAM_CALLBACK_MATCH_KEYS = [
|
|
|
584
671
|
"results"
|
|
585
672
|
];
|
|
586
673
|
function parseStreamCallbackMatch(raw) {
|
|
587
|
-
const r =
|
|
588
|
-
const radioId =
|
|
674
|
+
const r = asObjectLenient(raw);
|
|
675
|
+
const radioId = asInteger(r.radio_id);
|
|
589
676
|
const resultsRaw = Array.isArray(r.results) ? r.results : [];
|
|
590
677
|
const songs = resultsRaw.filter((x) => asObject(x) !== void 0).map(parseStreamCallbackSong);
|
|
591
678
|
const [first, ...rest] = songs;
|
|
592
679
|
return {
|
|
593
680
|
radioId,
|
|
594
681
|
timestamp: asString(r.timestamp),
|
|
595
|
-
playLength:
|
|
682
|
+
playLength: asInteger(r.play_length),
|
|
596
683
|
song: first,
|
|
597
684
|
alternatives: rest,
|
|
598
685
|
extras: pickExtras(r, STREAM_CALLBACK_MATCH_KEYS),
|
|
@@ -606,9 +693,9 @@ var STREAM_CALLBACK_NOTIFICATION_KEYS = [
|
|
|
606
693
|
"notification_message"
|
|
607
694
|
];
|
|
608
695
|
function parseStreamCallbackNotification(raw) {
|
|
609
|
-
const r =
|
|
610
|
-
const radioId =
|
|
611
|
-
const code =
|
|
696
|
+
const r = asObjectLenient(raw);
|
|
697
|
+
const radioId = asInteger(r.radio_id);
|
|
698
|
+
const code = asInteger(r.notification_code);
|
|
612
699
|
const message = asString(r.notification_message);
|
|
613
700
|
return {
|
|
614
701
|
radioId,
|
|
@@ -630,16 +717,16 @@ var LYRICS_KEYS = [
|
|
|
630
717
|
"media"
|
|
631
718
|
];
|
|
632
719
|
function parseLyricsResult(raw) {
|
|
633
|
-
const r =
|
|
720
|
+
const r = asObjectLenient(raw);
|
|
634
721
|
const artist = asString(r.artist);
|
|
635
722
|
const title = asString(r.title);
|
|
636
723
|
return {
|
|
637
724
|
artist,
|
|
638
725
|
title,
|
|
639
726
|
lyrics: asString(r.lyrics),
|
|
640
|
-
songId:
|
|
727
|
+
songId: asInteger(r.song_id),
|
|
641
728
|
fullTitle: asString(r.full_title),
|
|
642
|
-
artistId:
|
|
729
|
+
artistId: asInteger(r.artist_id),
|
|
643
730
|
songLink: asString(r.song_link),
|
|
644
731
|
media: asString(r.media),
|
|
645
732
|
extras: pickExtras(r, LYRICS_KEYS),
|
|
@@ -726,6 +813,22 @@ async function retry(fn, policy) {
|
|
|
726
813
|
if (haveResp && lastResp !== void 0) return lastResp;
|
|
727
814
|
throw lastError;
|
|
728
815
|
}
|
|
816
|
+
async function runRetried(fn, policy) {
|
|
817
|
+
try {
|
|
818
|
+
return await retry(fn, policy);
|
|
819
|
+
} catch (err) {
|
|
820
|
+
if (isUserAbortError(err)) {
|
|
821
|
+
throw new AudDConnectionError("Request was cancelled by the caller's AbortSignal", err);
|
|
822
|
+
}
|
|
823
|
+
if (err instanceof TypeError) {
|
|
824
|
+
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
825
|
+
}
|
|
826
|
+
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
827
|
+
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
828
|
+
}
|
|
829
|
+
throw err;
|
|
830
|
+
}
|
|
831
|
+
}
|
|
729
832
|
function looksLikeUrl(s) {
|
|
730
833
|
return s.startsWith("http://") || s.startsWith("https://");
|
|
731
834
|
}
|
|
@@ -977,13 +1080,13 @@ function decodeOne(resp) {
|
|
|
977
1080
|
);
|
|
978
1081
|
}
|
|
979
1082
|
const dict = body;
|
|
980
|
-
if (
|
|
1083
|
+
if (asObject(dict.notification) !== void 0) {
|
|
981
1084
|
const notification = parseStreamCallbackNotification(dict.notification);
|
|
982
1085
|
const t = dict["time"];
|
|
983
1086
|
if (typeof t === "number") notification.time = t;
|
|
984
1087
|
return { kind: "notification", notification };
|
|
985
1088
|
}
|
|
986
|
-
if (
|
|
1089
|
+
if (asObject(dict.result) !== void 0) {
|
|
987
1090
|
return { kind: "match", match: parseStreamCallbackMatch(dict.result) };
|
|
988
1091
|
}
|
|
989
1092
|
return { kind: "keepalive" };
|
|
@@ -1062,6 +1165,7 @@ function startLongpoll(cfg) {
|
|
|
1062
1165
|
|
|
1063
1166
|
// src/streams.ts
|
|
1064
1167
|
var API_BASE = "https://api.audd.io";
|
|
1168
|
+
var LONGPOLL_TIMEOUT_MARGIN_SEC = 10;
|
|
1065
1169
|
var NO_CALLBACK_ERROR_CODE = 19;
|
|
1066
1170
|
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.";
|
|
1067
1171
|
function decodeSuccess(body, httpStatus, requestId) {
|
|
@@ -1086,34 +1190,26 @@ function decodeSuccess(body, httpStatus, requestId) {
|
|
|
1086
1190
|
rawResponse: obj
|
|
1087
1191
|
});
|
|
1088
1192
|
}
|
|
1089
|
-
async function runRetried(fn, policy) {
|
|
1090
|
-
try {
|
|
1091
|
-
return await retry(fn, policy);
|
|
1092
|
-
} catch (err) {
|
|
1093
|
-
if (err instanceof TypeError) {
|
|
1094
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1095
|
-
}
|
|
1096
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1097
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1098
|
-
}
|
|
1099
|
-
throw err;
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
1193
|
var Streams = class {
|
|
1103
|
-
constructor(http, readPolicy, mutatingPolicy, apiToken) {
|
|
1194
|
+
constructor(http, readPolicy, mutatingPolicy, apiToken, onEvent) {
|
|
1104
1195
|
this.http = http;
|
|
1105
1196
|
this.readPolicy = readPolicy;
|
|
1106
1197
|
this.mutatingPolicy = mutatingPolicy;
|
|
1107
1198
|
this.apiToken = apiToken;
|
|
1199
|
+
this.onEvent = onEvent;
|
|
1108
1200
|
}
|
|
1109
1201
|
http;
|
|
1110
1202
|
readPolicy;
|
|
1111
1203
|
mutatingPolicy;
|
|
1112
1204
|
apiToken;
|
|
1205
|
+
onEvent;
|
|
1113
1206
|
async post(path2, fields, policy) {
|
|
1114
|
-
const
|
|
1115
|
-
|
|
1116
|
-
|
|
1207
|
+
const url = `${API_BASE}/${path2}/`;
|
|
1208
|
+
const resp = await emitAround(
|
|
1209
|
+
this.onEvent,
|
|
1210
|
+
path2,
|
|
1211
|
+
url,
|
|
1212
|
+
() => runRetried(() => this.http.postForm(url, fields), policy)
|
|
1117
1213
|
);
|
|
1118
1214
|
return decodeSuccess(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1119
1215
|
}
|
|
@@ -1160,11 +1256,11 @@ var Streams = class {
|
|
|
1160
1256
|
async list() {
|
|
1161
1257
|
const result = await this.post("getStreams", {}, this.readPolicy);
|
|
1162
1258
|
if (!Array.isArray(result)) return [];
|
|
1163
|
-
return result.map(parseStream);
|
|
1259
|
+
return result.filter((x) => asObject(x) !== void 0).map(parseStream);
|
|
1164
1260
|
}
|
|
1165
1261
|
/** Compute the 9-char longpoll category locally — pure, no network. */
|
|
1166
1262
|
deriveLongpollCategory(radioId) {
|
|
1167
|
-
return deriveLongpollCategory(this.apiToken, radioId);
|
|
1263
|
+
return deriveLongpollCategory(this.apiToken(), radioId);
|
|
1168
1264
|
}
|
|
1169
1265
|
/**
|
|
1170
1266
|
* Parse a callback POST body into `{ match, notification }`. Pass an
|
|
@@ -1206,13 +1302,21 @@ var Streams = class {
|
|
|
1206
1302
|
const timeoutSec = effectiveOpts.timeout ?? 50;
|
|
1207
1303
|
const httpClient = this.http;
|
|
1208
1304
|
const readPolicy = this.readPolicy;
|
|
1305
|
+
const onEvent = this.onEvent;
|
|
1306
|
+
const longpollUrl = `${API_BASE}/longpoll/`;
|
|
1307
|
+
const timeoutMs = (timeoutSec + LONGPOLL_TIMEOUT_MARGIN_SEC) * 1e3;
|
|
1209
1308
|
return startLongpoll({
|
|
1210
1309
|
category,
|
|
1211
1310
|
timeout: timeoutSec,
|
|
1212
1311
|
sinceTime: effectiveOpts.sinceTime,
|
|
1213
|
-
fetchOnce: (params, signal) =>
|
|
1214
|
-
|
|
1215
|
-
|
|
1312
|
+
fetchOnce: (params, signal) => emitAround(
|
|
1313
|
+
onEvent,
|
|
1314
|
+
"longpoll",
|
|
1315
|
+
longpollUrl,
|
|
1316
|
+
() => runRetried(
|
|
1317
|
+
() => httpClient.get(longpollUrl, params, { signal, timeoutMs }),
|
|
1318
|
+
readPolicy
|
|
1319
|
+
)
|
|
1216
1320
|
)
|
|
1217
1321
|
});
|
|
1218
1322
|
}
|
|
@@ -1257,26 +1361,15 @@ function decodeSuccess2(body, httpStatus, requestId) {
|
|
|
1257
1361
|
});
|
|
1258
1362
|
}
|
|
1259
1363
|
}
|
|
1260
|
-
async function runRetried2(fn, policy) {
|
|
1261
|
-
try {
|
|
1262
|
-
return await retry(fn, policy);
|
|
1263
|
-
} catch (err) {
|
|
1264
|
-
if (err instanceof TypeError) {
|
|
1265
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1266
|
-
}
|
|
1267
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1268
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1269
|
-
}
|
|
1270
|
-
throw err;
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
1364
|
var CustomCatalog = class {
|
|
1274
|
-
constructor(http, noRetryPolicy) {
|
|
1365
|
+
constructor(http, noRetryPolicy, onEvent) {
|
|
1275
1366
|
this.http = http;
|
|
1276
1367
|
this.noRetryPolicy = noRetryPolicy;
|
|
1368
|
+
this.onEvent = onEvent;
|
|
1277
1369
|
}
|
|
1278
1370
|
http;
|
|
1279
1371
|
noRetryPolicy;
|
|
1372
|
+
onEvent;
|
|
1280
1373
|
/**
|
|
1281
1374
|
* **This is NOT how you submit audio for music recognition.** For
|
|
1282
1375
|
* recognition, use `audd.recognize()` (or `audd.recognizeEnterprise()` for
|
|
@@ -1297,42 +1390,36 @@ var CustomCatalog = class {
|
|
|
1297
1390
|
async add(opts) {
|
|
1298
1391
|
const reopen = prepareSource(opts.source);
|
|
1299
1392
|
const audioId = String(opts.audioId);
|
|
1300
|
-
const resp = await
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1393
|
+
const resp = await emitAround(
|
|
1394
|
+
this.onEvent,
|
|
1395
|
+
"customCatalogAdd",
|
|
1396
|
+
UPLOAD_URL,
|
|
1397
|
+
() => runRetried(async () => {
|
|
1398
|
+
const prepared = await reopen();
|
|
1399
|
+
const fields = { ...prepared.fields, audio_id: audioId };
|
|
1400
|
+
return this.http.postForm(UPLOAD_URL, fields);
|
|
1401
|
+
}, this.noRetryPolicy)
|
|
1402
|
+
);
|
|
1305
1403
|
decodeSuccess2(resp.jsonBody, resp.httpStatus, resp.requestId);
|
|
1306
1404
|
}
|
|
1307
1405
|
};
|
|
1308
1406
|
|
|
1309
1407
|
// src/advanced.ts
|
|
1310
1408
|
var API_BASE2 = "https://api.audd.io";
|
|
1311
|
-
async function runRetried3(fn, policy) {
|
|
1312
|
-
try {
|
|
1313
|
-
return await retry(fn, policy);
|
|
1314
|
-
} catch (err) {
|
|
1315
|
-
if (err instanceof TypeError) {
|
|
1316
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1317
|
-
}
|
|
1318
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1319
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1320
|
-
}
|
|
1321
|
-
throw err;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
1409
|
var Advanced = class {
|
|
1325
1410
|
/**
|
|
1326
1411
|
* @param recognitionPolicy The findLyrics endpoint is metered and shouldn't
|
|
1327
1412
|
* double-bill on post-upload read timeout: Advanced uses RECOGNITION retry
|
|
1328
1413
|
* policy, not READ.
|
|
1329
1414
|
*/
|
|
1330
|
-
constructor(http, recognitionPolicy) {
|
|
1415
|
+
constructor(http, recognitionPolicy, onEvent) {
|
|
1331
1416
|
this.http = http;
|
|
1332
1417
|
this.recognitionPolicy = recognitionPolicy;
|
|
1418
|
+
this.onEvent = onEvent;
|
|
1333
1419
|
}
|
|
1334
1420
|
http;
|
|
1335
1421
|
recognitionPolicy;
|
|
1422
|
+
onEvent;
|
|
1336
1423
|
/** Find lyrics by free-text query. Returns a list of matches (possibly empty). */
|
|
1337
1424
|
async findLyrics(query) {
|
|
1338
1425
|
const body = await this.rawRequest("findLyrics", { q: query });
|
|
@@ -1356,9 +1443,12 @@ var Advanced = class {
|
|
|
1356
1443
|
if (v === void 0) continue;
|
|
1357
1444
|
fields[k] = String(v);
|
|
1358
1445
|
}
|
|
1359
|
-
const
|
|
1360
|
-
|
|
1361
|
-
this.
|
|
1446
|
+
const url = `${API_BASE2}/${method}/`;
|
|
1447
|
+
const resp = await emitAround(
|
|
1448
|
+
this.onEvent,
|
|
1449
|
+
method,
|
|
1450
|
+
url,
|
|
1451
|
+
() => runRetried(() => this.http.postForm(url, fields), this.recognitionPolicy)
|
|
1362
1452
|
);
|
|
1363
1453
|
const body = resp.jsonBody;
|
|
1364
1454
|
if (typeof body !== "object" || body === null || Array.isArray(body)) {
|
|
@@ -1374,13 +1464,6 @@ var ENTERPRISE_BASE = "https://enterprise.audd.io";
|
|
|
1374
1464
|
var DEPRECATED_PARAMS_CODE = 51;
|
|
1375
1465
|
var HTTP_CLIENT_ERROR_FLOOR2 = 400;
|
|
1376
1466
|
var TOKEN_ENV_VAR = "AUDD_API_TOKEN";
|
|
1377
|
-
function safeEmit(hook, event) {
|
|
1378
|
-
if (hook === void 0) return;
|
|
1379
|
-
try {
|
|
1380
|
-
hook(event);
|
|
1381
|
-
} catch {
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
1467
|
function resolveToken(apiToken) {
|
|
1385
1468
|
if (apiToken !== void 0 && apiToken !== "") return apiToken;
|
|
1386
1469
|
const env = (typeof process !== "undefined" ? process.env[TOKEN_ENV_VAR] : void 0) ?? "";
|
|
@@ -1453,7 +1536,7 @@ function decodeOrRaise(resp) {
|
|
|
1453
1536
|
function decodeRecognize(resp) {
|
|
1454
1537
|
const body = decodeOrRaise(resp);
|
|
1455
1538
|
const result = body["result"];
|
|
1456
|
-
if (result
|
|
1539
|
+
if (asObject(result) === void 0) return null;
|
|
1457
1540
|
return parseRecognitionResult(result);
|
|
1458
1541
|
}
|
|
1459
1542
|
function decodeEnterprise(resp) {
|
|
@@ -1462,24 +1545,12 @@ function decodeEnterprise(resp) {
|
|
|
1462
1545
|
if (!Array.isArray(chunks)) return [];
|
|
1463
1546
|
const out = [];
|
|
1464
1547
|
for (const c of chunks) {
|
|
1548
|
+
if (asObject(c) === void 0) continue;
|
|
1465
1549
|
const chunk = parseEnterpriseChunkResult(c);
|
|
1466
1550
|
out.push(...chunk.songs);
|
|
1467
1551
|
}
|
|
1468
1552
|
return out;
|
|
1469
1553
|
}
|
|
1470
|
-
async function runRetried4(fn, policy) {
|
|
1471
|
-
try {
|
|
1472
|
-
return await retry(fn, policy);
|
|
1473
|
-
} catch (err) {
|
|
1474
|
-
if (err instanceof TypeError) {
|
|
1475
|
-
throw new AudDConnectionError(`Network error: ${err.message}`, err);
|
|
1476
|
-
}
|
|
1477
|
-
if (err !== null && typeof err === "object" && err.name === "AbortError") {
|
|
1478
|
-
throw new AudDConnectionError("Request was aborted (timeout)", err);
|
|
1479
|
-
}
|
|
1480
|
-
throw err;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
1554
|
var AudD = class {
|
|
1484
1555
|
_http;
|
|
1485
1556
|
_enterpriseHttp;
|
|
@@ -1537,7 +1608,8 @@ var AudD = class {
|
|
|
1537
1608
|
this._http,
|
|
1538
1609
|
this.policyFor("read"),
|
|
1539
1610
|
this.policyFor("mutating"),
|
|
1540
|
-
this._apiToken
|
|
1611
|
+
() => this._apiToken,
|
|
1612
|
+
this._onEvent
|
|
1541
1613
|
);
|
|
1542
1614
|
}
|
|
1543
1615
|
return this._streams;
|
|
@@ -1545,14 +1617,14 @@ var AudD = class {
|
|
|
1545
1617
|
/** Sub-namespace for the private fingerprint catalog. NOT for recognition. */
|
|
1546
1618
|
get customCatalog() {
|
|
1547
1619
|
if (this._customCatalog === void 0) {
|
|
1548
|
-
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"));
|
|
1620
|
+
this._customCatalog = new CustomCatalog(this._http, this.policyFor("none"), this._onEvent);
|
|
1549
1621
|
}
|
|
1550
1622
|
return this._customCatalog;
|
|
1551
1623
|
}
|
|
1552
1624
|
/** Lyrics search + raw-request escape hatch. */
|
|
1553
1625
|
get advanced() {
|
|
1554
1626
|
if (this._advanced === void 0) {
|
|
1555
|
-
this._advanced = new Advanced(this._http, this.policyFor("recognition"));
|
|
1627
|
+
this._advanced = new Advanced(this._http, this.policyFor("recognition"), this._onEvent);
|
|
1556
1628
|
}
|
|
1557
1629
|
return this._advanced;
|
|
1558
1630
|
}
|
|
@@ -1568,20 +1640,11 @@ var AudD = class {
|
|
|
1568
1640
|
const market = opts.market;
|
|
1569
1641
|
const policy = this.policyFor("recognition");
|
|
1570
1642
|
const url = `${API_BASE3}/`;
|
|
1571
|
-
const
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
method: "recognize",
|
|
1643
|
+
const resp = await emitAround(
|
|
1644
|
+
this._onEvent,
|
|
1645
|
+
"recognize",
|
|
1575
1646
|
url,
|
|
1576
|
-
|
|
1577
|
-
httpStatus: null,
|
|
1578
|
-
elapsedMs: null,
|
|
1579
|
-
errorCode: null,
|
|
1580
|
-
extras: {}
|
|
1581
|
-
});
|
|
1582
|
-
let resp;
|
|
1583
|
-
try {
|
|
1584
|
-
resp = await runRetried4(async () => {
|
|
1647
|
+
() => runRetried(async () => {
|
|
1585
1648
|
const prepared = await reopen();
|
|
1586
1649
|
const fields = { ...prepared.fields };
|
|
1587
1650
|
if (opts.extraParameters) Object.assign(fields, opts.extraParameters);
|
|
@@ -1591,30 +1654,8 @@ var AudD = class {
|
|
|
1591
1654
|
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1592
1655
|
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1593
1656
|
});
|
|
1594
|
-
}, policy)
|
|
1595
|
-
|
|
1596
|
-
safeEmit(this._onEvent, {
|
|
1597
|
-
kind: "exception",
|
|
1598
|
-
method: "recognize",
|
|
1599
|
-
url,
|
|
1600
|
-
requestId: null,
|
|
1601
|
-
httpStatus: null,
|
|
1602
|
-
elapsedMs: Date.now() - startedAt,
|
|
1603
|
-
errorCode: null,
|
|
1604
|
-
extras: { name: err instanceof Error ? err.name : String(err) }
|
|
1605
|
-
});
|
|
1606
|
-
throw err;
|
|
1607
|
-
}
|
|
1608
|
-
safeEmit(this._onEvent, {
|
|
1609
|
-
kind: "response",
|
|
1610
|
-
method: "recognize",
|
|
1611
|
-
url,
|
|
1612
|
-
requestId: resp.requestId,
|
|
1613
|
-
httpStatus: resp.httpStatus,
|
|
1614
|
-
elapsedMs: Date.now() - startedAt,
|
|
1615
|
-
errorCode: null,
|
|
1616
|
-
extras: {}
|
|
1617
|
-
});
|
|
1657
|
+
}, policy)
|
|
1658
|
+
);
|
|
1618
1659
|
return decodeRecognize(resp);
|
|
1619
1660
|
}
|
|
1620
1661
|
/**
|
|
@@ -1627,14 +1668,20 @@ var AudD = class {
|
|
|
1627
1668
|
const reopen = prepareSource(source);
|
|
1628
1669
|
const extra = buildEnterpriseFields(opts);
|
|
1629
1670
|
const policy = this.policyFor("recognition");
|
|
1630
|
-
const
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1671
|
+
const url = `${ENTERPRISE_BASE}/`;
|
|
1672
|
+
const resp = await emitAround(
|
|
1673
|
+
this._onEvent,
|
|
1674
|
+
"recognizeEnterprise",
|
|
1675
|
+
url,
|
|
1676
|
+
() => runRetried(async () => {
|
|
1677
|
+
const prepared = await reopen();
|
|
1678
|
+
const fields = { ...prepared.fields, ...extra };
|
|
1679
|
+
return this._enterpriseHttp.postForm(url, fields, {
|
|
1680
|
+
...opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : {},
|
|
1681
|
+
...opts.signal !== void 0 ? { signal: opts.signal } : {}
|
|
1682
|
+
});
|
|
1683
|
+
}, policy)
|
|
1684
|
+
);
|
|
1638
1685
|
return decodeEnterprise(resp);
|
|
1639
1686
|
}
|
|
1640
1687
|
/** Release any underlying resources. (Currently a no-op for `fetch`-based transport.) */
|