musicbrainz-api 1.0.0 → 1.1.0
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 +1 -1
- package/lib/http-client.js +7 -2
- package/lib/musicbrainz-api.d.ts +12 -0
- package/lib/musicbrainz-api.js +48 -2
- package/package.json +2 -2
package/README.md
CHANGED
package/lib/http-client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Debug from "debug";
|
|
2
|
-
const debug = Debug('musicbrainz-api-
|
|
2
|
+
const debug = Debug('musicbrainz-api:http-client');
|
|
3
3
|
function isConnectionReset(err) {
|
|
4
4
|
// Undici puts the OS error on .cause, with .code like 'ECONNRESET'
|
|
5
5
|
const code = err?.cause?.code ?? err?.code;
|
|
@@ -18,7 +18,11 @@ export class HttpClient {
|
|
|
18
18
|
}
|
|
19
19
|
postForm(path, formData, options) {
|
|
20
20
|
const encodedFormData = new URLSearchParams(formData).toString();
|
|
21
|
-
return this._fetch('post', path, {
|
|
21
|
+
return this._fetch('post', path, {
|
|
22
|
+
...options,
|
|
23
|
+
body: encodedFormData,
|
|
24
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
25
|
+
});
|
|
22
26
|
}
|
|
23
27
|
postJson(path, json, options) {
|
|
24
28
|
const encodedJson = JSON.stringify(json);
|
|
@@ -63,6 +67,7 @@ export class HttpClient {
|
|
|
63
67
|
continue;
|
|
64
68
|
}
|
|
65
69
|
}
|
|
70
|
+
debug(`Received status=${response.status}`);
|
|
66
71
|
await this.registerCookies(response);
|
|
67
72
|
return response;
|
|
68
73
|
}
|
package/lib/musicbrainz-api.d.ts
CHANGED
|
@@ -87,6 +87,18 @@ export interface ISessionInformation {
|
|
|
87
87
|
csrf: ICsrfSession;
|
|
88
88
|
loggedIn?: boolean;
|
|
89
89
|
}
|
|
90
|
+
export declare class MusicBrainzApiError extends Error {
|
|
91
|
+
readonly status: number;
|
|
92
|
+
readonly statusText: string;
|
|
93
|
+
readonly body?: unknown;
|
|
94
|
+
readonly url?: string;
|
|
95
|
+
constructor(message: string, opts: {
|
|
96
|
+
status: number;
|
|
97
|
+
statusText: string;
|
|
98
|
+
body?: unknown;
|
|
99
|
+
url?: string;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
90
102
|
export declare class MusicBrainzApi {
|
|
91
103
|
readonly config: IInternalConfig;
|
|
92
104
|
protected rateLimiter: RateLimitThreshold;
|
package/lib/musicbrainz-api.js
CHANGED
|
@@ -10,6 +10,25 @@ export { XmlIsrcList } from './xml/xml-isrc-list.js';
|
|
|
10
10
|
export { XmlRecording } from './xml/xml-recording.js';
|
|
11
11
|
export * from './musicbrainz.types.js';
|
|
12
12
|
const debug = Debug('musicbrainz-api');
|
|
13
|
+
async function safeJson(res) {
|
|
14
|
+
// Some responses might not be JSON, or the client may have already consumed the body.
|
|
15
|
+
try {
|
|
16
|
+
return await res.json();
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class MusicBrainzApiError extends Error {
|
|
23
|
+
constructor(message, opts) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "MusicBrainzApiError";
|
|
26
|
+
this.status = opts.status;
|
|
27
|
+
this.statusText = opts.statusText;
|
|
28
|
+
this.body = opts.body;
|
|
29
|
+
this.url = opts.url;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
13
32
|
export class MusicBrainzApi {
|
|
14
33
|
static fetchCsrf(html) {
|
|
15
34
|
return {
|
|
@@ -53,6 +72,20 @@ export class MusicBrainzApi {
|
|
|
53
72
|
query,
|
|
54
73
|
retryLimit: 10
|
|
55
74
|
});
|
|
75
|
+
if (response.status === 400) {
|
|
76
|
+
const body = await safeJson(response);
|
|
77
|
+
const mb = (body ?? {});
|
|
78
|
+
// Prefer the API-provided message when available.
|
|
79
|
+
const message = mb.error
|
|
80
|
+
? `MusicBrainz request failed (${response.status}): ${mb.error}`
|
|
81
|
+
: `MusicBrainz request failed (${response.status}): ${response.statusText}`;
|
|
82
|
+
throw new MusicBrainzApiError(message, {
|
|
83
|
+
status: response.status,
|
|
84
|
+
statusText: response.statusText,
|
|
85
|
+
body,
|
|
86
|
+
url: response.url,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
56
89
|
return response.json();
|
|
57
90
|
}
|
|
58
91
|
lookup(entity, mbid, inc = []) {
|
|
@@ -83,7 +116,7 @@ export class MusicBrainzApi {
|
|
|
83
116
|
}
|
|
84
117
|
return this.restGet(`/${entity}`, query);
|
|
85
118
|
}
|
|
86
|
-
search(entity, query) {
|
|
119
|
+
async search(entity, query) {
|
|
87
120
|
const urlQuery = { ...query };
|
|
88
121
|
if (typeof query.query === 'object') {
|
|
89
122
|
urlQuery.query = makeAndQueryString(query.query);
|
|
@@ -91,7 +124,20 @@ export class MusicBrainzApi {
|
|
|
91
124
|
if (Array.isArray(query.inc)) {
|
|
92
125
|
urlQuery.inc = urlQuery.inc.join(' ');
|
|
93
126
|
}
|
|
94
|
-
|
|
127
|
+
const result = await this.restGet(`/${entity}/`, urlQuery);
|
|
128
|
+
// Temporary workaround for https://tickets.metabrainz.org/browse/SEARCH-444
|
|
129
|
+
// Should be resolved by https://github.com/metabrainz/mb-solr/pull/69
|
|
130
|
+
if (entity === 'url') {
|
|
131
|
+
// @ts-expect-error
|
|
132
|
+
result.urls.forEach(url => {
|
|
133
|
+
// @ts-expect-error
|
|
134
|
+
if (!url.relations && url['relation-list']) {
|
|
135
|
+
// @ts-expect-error
|
|
136
|
+
url.relations = url['relation-list'];
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
95
141
|
}
|
|
96
142
|
// ---------------------------------------------------------------------------
|
|
97
143
|
async postRecording(xmlMetadata) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "musicbrainz-api",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "MusicBrainz API client for reading and submitting metadata",
|
|
5
5
|
"exports": {
|
|
6
6
|
"node": {
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"uuid": "^13.0.0"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@biomejs/biome": "2.3.
|
|
64
|
+
"@biomejs/biome": "2.3.14",
|
|
65
65
|
"@types/chai": "^5.0.0",
|
|
66
66
|
"@types/jsontoxml": "^1.0.5",
|
|
67
67
|
"@types/mocha": "^10.0.4",
|