musicbrainz-api 0.13.0 → 0.15.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 CHANGED
@@ -2,7 +2,7 @@
2
2
  [![NPM version](https://img.shields.io/npm/v/musicbrainz-api.svg)](https://npmjs.org/package/musicbrainz-api)
3
3
  [![npm downloads](http://img.shields.io/npm/dm/musicbrainz-api.svg)](https://npmcharts.com/compare/musicbrainz-api?interval=30&start=365)
4
4
  [![Coverage Status](https://coveralls.io/repos/github/Borewit/musicbrainz-api/badge.svg?branch=master)](https://coveralls.io/github/Borewit/musicbrainz-api?branch=master)
5
- [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2bc47b2006454bae8c737991f152e518)](https://www.codacy.com/gh/Borewit/musicbrainz-api/dashboard?utm_source=github.com&utm_medium=referral&utm_content=Borewit/musicbrainz-api&utm_campaign=Badge_Grade)
5
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2bc47b2006454bae8c737991f152e518)](https://app.codacy.com/gh/Borewit/musicbrainz-api/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
6
6
  [![CodeQL](https://github.com/Borewit/musicbrainz-api/actions/workflows/codeql.yml/badge.svg)](https://github.com/Borewit/musicbrainz-api/actions/workflows/codeql.yml)
7
7
  [![Known Vulnerabilities](https://snyk.io/test/github/Borewit/musicbrainz-api/badge.svg?targetFile=package.json)](https://snyk.io/test/github/Borewit/musicbrainz-api?targetFile=package.json)
8
8
  [![DeepScan grade](https://deepscan.io/api/teams/5165/projects/6991/branches/63373/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=5165&pid=6991&bid=63373)
@@ -82,106 +82,14 @@ MusicBrainz API documentation: [XML Web Service/Version 2 Lookups](https://wiki.
82
82
  ### Generic lookup function
83
83
 
84
84
  Arguments:
85
- * entity: `'artist'` | `'label'` | `'recording'` | `'release'` | `'release-group'` | `'work'` | `'area'` | `'url'`
85
+ * entity: `'area'` | `'artist'` | `'collection'` | `'instrument'` | `'label'` | `'place'` | `'release'` | `'release-group'` | `'recording'` | `'series'` | `'work'` | `'url'` | `'event'`
86
86
  * MBID [(MusicBrainz identifier)](https://wiki.musicbrainz.org/MusicBrainz_Identifier)
87
+ * query
87
88
 
88
89
  ```js
89
- const artist = await mbApi.lookupEntity('artist', 'ab2528d9-719f-4261-8098-21849222a0f2');
90
+ const artist = await mbApi.lookup('artist', 'ab2528d9-719f-4261-8098-21849222a0f2');
90
91
  ```
91
92
 
92
- ### Lookup area
93
-
94
- ```js
95
- const area = await mbApi.lookupArea('ab2528d9-719f-4261-8098-21849222a0f2');
96
- ```
97
-
98
- ### Lookup artist
99
-
100
- Lookup an `artist` and include their `releases`, `release-groups` and `aliases`
101
-
102
- ```js
103
- const artist = await mbApi.lookupArtist('ab2528d9-719f-4261-8098-21849222a0f2');
104
- ```
105
-
106
- ### Lookup collection
107
-
108
- Lookup an instrument
109
-
110
- ```js
111
- const collection = await mbApi.lookupCollection('de4fdfc4-53aa-458a-b463-8761cc7f5af8');
112
- ```
113
-
114
- Lookup an event
115
-
116
- ```js
117
- const event = await mbApi.lookupEvent('6d32c658-151e-45ec-88c4-fb8787524d61');
118
- ```
119
-
120
- ### Lookup instrument
121
-
122
- Lookup an instrument
123
-
124
- ```js
125
- const instrument = await mbApi.lookupInstrument('b3eac5f9-7859-4416-ac39-7154e2e8d348');
126
- ```
127
-
128
- ### Lookup label
129
-
130
- Lookup a label
131
-
132
- ```js
133
- const label = await mbApi.lookupLabel('25dda9f9-f069-4898-82f0-59330a106c7f');
134
- ```
135
-
136
- ### Lookup place
137
-
138
- ```js
139
- const place = await mbApi.lookupPlace('e6cfb74d-d69b-44c3-b890-1b3f509816e4');
140
- ```
141
-
142
- ```js
143
- const place = await mbApi.lookupSeries('1ae6c9bc-2931-4d75-bee4-3dc53dfd246a');
144
- ```
145
-
146
- The second argument can be used to pass [subqueries](https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Subqueries), which will return more (nested) information:
147
- ```js
148
- const artist = await mbApi.lookupArtist('ab2528d9-719f-4261-8098-21849222a0f2', ['releases', 'recordings', 'url-rels']);
149
- ```
150
-
151
- ### Lookup recording
152
-
153
- The second argument can be used to pass [subqueries](https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Subqueries):
154
- ```js
155
- const recording = await mbApi.lookupRecording('16afa384-174e-435e-bfa3-5591accda31c', ['artists', 'url-rels']);
156
- ```
157
-
158
- ### Lookup release
159
- ```js
160
- const release = await mbApi.lookupRelease('976e0677-a480-4a5e-a177-6a86c1900bbf', ['artists', 'url-rels']);
161
- ```
162
-
163
- ### Lookup release-group
164
- ```js
165
- const releaseGroup = await mbApi.lookupReleaseGroup('19099ea5-3600-4154-b482-2ec68815883e');
166
- ```
167
-
168
- ### Lookup work
169
- ```js
170
- const work = await mbApi.lookupWork('b2aa02f4-6c95-43be-a426-aedb9f9a3805');
171
- ```
172
-
173
- ### Lookup URL
174
- ```js
175
- const url = await mbApi.lookupUrl('c69556a6-7ded-4c54-809c-afb45a1abe7d');
176
- ```
177
-
178
- ## Browse entities
179
-
180
- ### Browse area
181
-
182
- ```js
183
- const area = await browseAreas(query);
184
- ````
185
93
 
186
94
  | Query argument | Query value |
187
95
  |-----------------------|-----------------|
@@ -190,7 +98,7 @@ const area = await browseAreas(query);
190
98
  ### Browse artist
191
99
 
192
100
  ```js
193
- const artist = await browseArtist(query);
101
+ const artists = await mbApi.browse('artist', query);
194
102
  ````
195
103
 
196
104
  | Query argument | Query value |
@@ -204,7 +112,7 @@ const artist = await browseArtist(query);
204
112
 
205
113
  ### Browse collection
206
114
  ```js
207
- const artist = await browseCollection(query);
115
+ const collections = await mbApi.browse('collection', query);
208
116
  ````
209
117
 
210
118
  | Query argument | Query value |
@@ -222,7 +130,7 @@ const artist = await browseCollection(query);
222
130
 
223
131
  ### Browse events
224
132
  ```js
225
- const events = await browseEvents(query);
133
+ const events = await mbApi.browse('event', query);
226
134
  ````
227
135
 
228
136
  | Query argument | Query value |
@@ -234,7 +142,7 @@ const events = await browseEvents(query);
234
142
 
235
143
  ### Browse instruments
236
144
  ```js
237
- const instruments = await browseEvents(query);
145
+ const instruments = await mbApi.browse('event', query);
238
146
  ````
239
147
 
240
148
  | Query argument | Query value |
@@ -243,7 +151,7 @@ const instruments = await browseEvents(query);
243
151
 
244
152
  ### Browse labels
245
153
  ```js
246
- const labels = await browseLabels(query);
154
+ const labels = await mbApi.browse('label', query);
247
155
  ````
248
156
 
249
157
  | Query argument | Query value |
@@ -254,7 +162,7 @@ const labels = await browseLabels(query);
254
162
 
255
163
  ### Browse places
256
164
  ```js
257
- const places = await browsePlaces(query);
165
+ const places = await mbApi.browse('place', query);
258
166
  ````
259
167
 
260
168
  | Query argument | Query value |
@@ -264,7 +172,7 @@ const places = await browsePlaces(query);
264
172
 
265
173
  ### Browse recordings
266
174
  ```js
267
- const recordings = await browseRecordings(query);
175
+ const recordings = await mbApi.browse('recording', query);
268
176
  ````
269
177
 
270
178
  | Query argument | Query value |
@@ -276,7 +184,7 @@ const recordings = await browseRecordings(query);
276
184
 
277
185
  ### Browse releases
278
186
  ```js
279
- const places = await browseReleases(query);
187
+ const releases = await mbApi.browse('release', query);
280
188
  ````
281
189
 
282
190
  | Query argument | Query value |
@@ -294,7 +202,7 @@ const places = await browseReleases(query);
294
202
 
295
203
  ### Browse release-groups
296
204
  ```js
297
- const places = await browseReleaseGroups(query);
205
+ const releaseGroups = await mbApi.browse('release-group',query);
298
206
  ```
299
207
 
300
208
  | Query argument | Query value |
@@ -305,7 +213,7 @@ const places = await browseReleaseGroups(query);
305
213
 
306
214
  ### Browse series
307
215
  ```js
308
- const places = await browseSeries();
216
+ const series = await mbApi.browse('series');
309
217
  ````
310
218
 
311
219
  | Query argument | Query value |
@@ -323,7 +231,7 @@ const places = await browseSeries();
323
231
 
324
232
  ### Browse works
325
233
  ```js
326
- const places = await browseWorks();
234
+ const works = await mbApi.browse('work');
327
235
  ````
328
236
 
329
237
  | Query argument | Query value |
@@ -333,7 +241,7 @@ const places = await browseWorks();
333
241
 
334
242
  ### Browse urls
335
243
  ```js
336
- const urls = await browseUrls();
244
+ const urls = await mbApi.browse('url');
337
245
  ````
338
246
 
339
247
  | Query argument | Query value |
@@ -347,9 +255,9 @@ Implements [XML Web Service/Version 2/Search](https://wiki.musicbrainz.org/Devel
347
255
 
348
256
  There are different search fields depending on the entity.
349
257
 
350
- ### Generic search function
258
+ ### Search function
351
259
 
352
- Searches can be performed using the generic search function: `query(entity: mb.EntityType, query: string | IFormData, offset?: number, limit?: number)`
260
+ Searches can be performed using the generic search function: `query(entity: mb.EntityType, query: string | IFormData, offset?: number, limit?: number): Promise<entity>`
353
261
 
354
262
  Arguments:
355
263
  * Entity type, which can be one of:
@@ -369,7 +277,7 @@ Arguments:
369
277
  For example, to find any recordings of _'We Will Rock You'_ by Queen:
370
278
  ```js
371
279
  const query = 'query="We Will Rock You" AND arid:0383dadf-2a4e-4d10-a46a-e9e041da8eb3';
372
- const result = await mbApi.query<mb.IReleaseGroupList>('release-group', {query});
280
+ const result = await mbApi.search('release-group', {query});
373
281
  ```
374
282
 
375
283
  ##### Example: search Île-de-France
@@ -392,27 +300,25 @@ Same as previous example, but automatically serialize parameters to search query
392
300
  mbApi.search('release', 'barcode: 602537479870');
393
301
  ````
394
302
 
395
- ### Entity specific search functions
396
-
397
- The following entity specific search functions are available:
398
- ```TypeScript
399
- searchArtist(query: string | IFormData, offset?: number, limit?: number): Promise<mb.IArtistList>
400
- searchReleaseGroup(query: string | IFormData, offset?: number, limit?: number): Promise<mb.IReleaseGroupList>`
401
- ```
303
+ ##### Example: search artist by artist name
402
304
 
403
305
  Search artist:
404
306
  ```js
405
- const result = await mbApi.searchArtist({query: 'Stromae'});
307
+ const result = await mbApi.search('artist', {query: 'Stromae'});
406
308
  ```
407
309
 
310
+ ##### Example: search release-group by artist name
311
+
408
312
  Search release-group:
409
313
  ```js
410
- const result = await mbApi.searchReleaseGroup({query: 'Racine carrée'});
314
+ const result = await mbApi.search('release-group', {query: 'Racine carrée'});
411
315
  ```
412
316
 
317
+ ##### Example: search release-group by release-group and an artist
318
+
413
319
  Search a combination of a release-group and an artist.
414
320
  ```js
415
- const result = await mbApi.searchReleaseGroup({artist: 'Racine carrée', releasegroup: 'Stromae'});
321
+ const result = await mbApi.search('release-group', {artist: 'Racine carrée', releasegroup: 'Stromae'});
416
322
  ```
417
323
 
418
324
  # Submitting data via XML POST
@@ -439,7 +345,7 @@ For all of the following function you need to use a dedicated bot account.
439
345
 
440
346
  ## Submitting ISRC via post user form-data
441
347
 
442
- <img width="150" src="http://www.clker.com/cliparts/i/w/L/q/u/1/work-in-progress.svg"/>
348
+ <img width="150" src="http://www.clker.com/cliparts/i/w/L/q/u/1/work-in-progress.svg" alt="Work in progress"/>
443
349
  Use with caution, and only on a test server, it may clear existing metadata as side effect.
444
350
 
445
351
  ```js
@@ -448,7 +354,7 @@ const mbid_Formidable = '16afa384-174e-435e-bfa3-5591accda31c';
448
354
  const isrc_Formidable = 'BET671300161';
449
355
 
450
356
 
451
- const recording = await mbApi.lookupRecording(mbid_Formidable);
357
+ const recording = await mbApi.lookup('recording', mbid_Formidable);
452
358
 
453
359
  // Authentication the http-session against MusicBrainz (as defined in config.baseUrl)
454
360
  const succeed = await mbApi.login();
@@ -461,7 +367,7 @@ await mbApi.addIsrc(recording, isrc_Formidable);
461
367
  ### Submit recording URL
462
368
 
463
369
  ```js
464
- const recording = await mbApi.lookupRecording('16afa384-174e-435e-bfa3-5591accda31c');
370
+ const recording = await mbApi.lookup('recording', '16afa384-174e-435e-bfa3-5591accda31c');
465
371
 
466
372
  const succeed = await mbApi.login();
467
373
  assert.isTrue(succeed, 'Login successful');
@@ -474,7 +380,7 @@ await mbApi.addUrlToRecording(recording, {
474
380
 
475
381
  Actually a Spotify-track-ID can be submitted easier:
476
382
  ```js
477
- const recording = await mbApi.lookupRecording('16afa384-174e-435e-bfa3-5591accda31c');
383
+ const recording = await mbApi.lookup('recording', '16afa384-174e-435e-bfa3-5591accda31c');
478
384
 
479
385
  const succeed = await mbApi.login();
480
386
  assert.isTrue(succeed, 'Login successful');
@@ -24,8 +24,25 @@ export declare class CoverArtArchiveApi {
24
24
  private host;
25
25
  private getJson;
26
26
  /**
27
- *
27
+ * Fetch release
28
+ * @releaseId Release MBID
28
29
  * @param releaseId MusicBrainz Release MBID
30
+ * @param coverType Cover type
29
31
  */
30
32
  getReleaseCovers(releaseId: string, coverType?: 'front' | 'back'): Promise<ICoverInfo>;
33
+ /**
34
+ * Fetch release-group
35
+ * @releaseGroupId Release-group MBID
36
+ * @param releaseGroupId MusicBrainz Release Group MBID
37
+ * @param coverType Cover type
38
+ */
39
+ getReleaseGroupCovers(releaseGroupId: string, coverType?: 'front' | 'back'): Promise<ICoverInfo>;
40
+ /**
41
+ * Fetch covers
42
+ * @releaseId MBID
43
+ * @param releaseId MusicBrainz Release Group MBID
44
+ * @param releaseType Fetch covers for specific release or release-group
45
+ * @param coverType Cover type
46
+ */
47
+ private getCovers;
31
48
  }
@@ -14,11 +14,32 @@ export class CoverArtArchiveApi {
14
14
  return response.body;
15
15
  }
16
16
  /**
17
- *
17
+ * Fetch release
18
+ * @releaseId Release MBID
18
19
  * @param releaseId MusicBrainz Release MBID
20
+ * @param coverType Cover type
19
21
  */
20
- async getReleaseCovers(releaseId, coverType) {
21
- const path = ['release', releaseId];
22
+ getReleaseCovers(releaseId, coverType) {
23
+ return this.getCovers(releaseId, 'release', coverType);
24
+ }
25
+ /**
26
+ * Fetch release-group
27
+ * @releaseGroupId Release-group MBID
28
+ * @param releaseGroupId MusicBrainz Release Group MBID
29
+ * @param coverType Cover type
30
+ */
31
+ getReleaseGroupCovers(releaseGroupId, coverType) {
32
+ return this.getCovers(releaseGroupId, 'release-group', coverType);
33
+ }
34
+ /**
35
+ * Fetch covers
36
+ * @releaseId MBID
37
+ * @param releaseId MusicBrainz Release Group MBID
38
+ * @param releaseType Fetch covers for specific release or release-group
39
+ * @param coverType Cover type
40
+ */
41
+ async getCovers(releaseId, releaseType = 'release', coverType) {
42
+ const path = [releaseType, releaseId];
22
43
  if (coverType) {
23
44
  path.push(coverType);
24
45
  }
@@ -37,7 +37,7 @@ export type InstrumentIncludes = MiscIncludes | RelationsIncludes;
37
37
  export type LabelIncludes = MiscIncludes | RelationsIncludes | 'releases';
38
38
  export type PlaceIncludes = MiscIncludes | RelationsIncludes;
39
39
  export type RecordingIncludes = MiscIncludes | RelationsIncludes | SubQueryIncludes | 'artists' | 'releases' | 'isrcs';
40
- export type ReleasesIncludes = MiscIncludes | SubQueryIncludes | RelationsIncludes | 'artists' | 'collections' | 'labels' | 'recordings' | 'release-groups';
40
+ export type ReleaseIncludes = MiscIncludes | SubQueryIncludes | RelationsIncludes | 'artists' | 'collections' | 'labels' | 'recordings' | 'release-groups';
41
41
  export type ReleaseGroupIncludes = MiscIncludes | SubQueryIncludes | RelationsIncludes | 'artists' | 'releases';
42
42
  export type SeriesIncludes = MiscIncludes | RelationsIncludes;
43
43
  export type WorkIncludes = MiscIncludes | RelationsIncludes;
@@ -46,7 +46,7 @@ export type IFormData = {
46
46
  [key: string]: string | number;
47
47
  };
48
48
  export interface IMusicBrainzConfig {
49
- botAccount: {
49
+ botAccount?: {
50
50
  username?: string;
51
51
  password?: string;
52
52
  };
@@ -71,7 +71,6 @@ export interface ISessionInformation {
71
71
  loggedIn?: boolean;
72
72
  }
73
73
  export declare class MusicBrainzApi {
74
- private static escapeText;
75
74
  readonly config: IMusicBrainzConfig;
76
75
  private rateLimiter;
77
76
  private options;
@@ -82,164 +81,60 @@ export declare class MusicBrainzApi {
82
81
  constructor(_config?: IMusicBrainzConfig);
83
82
  restGet<T>(relUrl: string, query?: {
84
83
  [key: string]: any;
85
- }, attempt?: number): Promise<T>;
86
- /**
87
- * Generic lookup function
88
- * @param entity
89
- * @param mbid
90
- * @param inc
91
- */
92
- lookupEntity<T, I extends string = never>(entity: mb.EntityType, mbid: string, inc?: I[]): Promise<T>;
93
- /**
94
- * Lookup area
95
- * @param areaId Area MBID
96
- * @param inc Sub-queries
97
- */
98
- lookupArea(areaId: string, inc?: AreaIncludes[]): Promise<mb.IArea>;
99
- /**
100
- * Lookup artist
101
- * @param artistId Artist MBID
102
- * @param inc Sub-queries
103
- */
104
- lookupArtist(artistId: string, inc?: ArtistIncludes[]): Promise<mb.IArtist>;
105
- /**
106
- * Lookup collection
107
- * @param collectionId Collection MBID
108
- * @param inc List of additional information to be included about the entity. Any of the entities directly linked to the entity can be included.
109
- */
110
- lookupCollection(collectionId: string, inc?: ArtistIncludes[]): Promise<mb.ICollection>;
111
- /**
112
- * Lookup instrument
113
- * @param artistId Instrument MBID
114
- * @param inc Sub-queries
115
- */
116
- lookupInstrument(instrumentId: string, inc?: InstrumentIncludes[]): Promise<mb.IInstrument>;
117
- /**
118
- * Lookup label
119
- * @param labelId Area MBID
120
- * @param inc Sub-queries
121
- */
122
- lookupLabel(labelId: string, inc?: LabelIncludes[]): Promise<mb.ILabel>;
123
- /**
124
- * Lookup place
125
- * @param placeId Area MBID
126
- * @param inc Sub-queries
127
- */
128
- lookupPlace(placeId: string, inc?: PlaceIncludes[]): Promise<mb.IPlace>;
129
- /**
130
- * Lookup release
131
- * @param releaseId Release MBID
132
- * @param inc Include: artist-credits, labels, recordings, release-groups, media, discids, isrcs (with recordings)
133
- * ToDo: ['recordings', 'artists', 'artist-credits', 'isrcs', 'url-rels', 'release-groups']
134
- */
135
- lookupRelease(releaseId: string, inc?: ReleasesIncludes[]): Promise<mb.IRelease>;
136
- /**
137
- * Lookup release-group
138
- * @param releaseGroupId Release-group MBID
139
- * @param inc Include: ToDo
140
- */
141
- lookupReleaseGroup(releaseGroupId: string, inc?: ReleaseGroupIncludes[]): Promise<mb.IReleaseGroup>;
142
- /**
143
- * Lookup recording
144
- * @param recordingId Label MBID
145
- * @param inc Include: artist-credits, isrcs
146
- */
147
- lookupRecording(recordingId: string, inc?: RecordingIncludes[]): Promise<mb.IRecording>;
148
- /**
149
- * Lookup series
150
- * @param seriesId Series MBID
151
- */
152
- lookupSeries(seriesId: string): Promise<mb.ISeries>;
153
- /**
154
- * Lookup work
155
- * @param workId Work MBID
156
- */
157
- lookupWork(workId: string, inc?: WorkIncludes[]): Promise<mb.IWork>;
158
- /**
159
- * Lookup URL
160
- * @param urlId URL MBID
161
- */
162
- lookupUrl(urlId: string, inc?: UrlIncludes[]): Promise<mb.IUrl>;
163
- /**
164
- * Lookup Event
165
- * @param eventId Event MBID
166
- * @param eventIncludes List of sub-queries to enable
167
- */
168
- lookupEvent(eventId: string, eventIncludes?: EventIncludes[]): Promise<mb.IEvent>;
84
+ }): Promise<T>;
169
85
  /**
170
- * Generic browse function
86
+ * Lookup entity
87
+ * @param entity 'area', 'artist', collection', 'instrument', 'label', 'place', 'release', 'release-group', 'recording', 'series', 'work', 'url' or 'event'
88
+ * @param mbid Entity MBID
89
+ * @param inc Query, like: {<entity>: <MBID:}
90
+ */
91
+ lookup(entity: 'area', mbid: string, inc?: AreaIncludes[]): Promise<mb.IArea>;
92
+ lookup(entity: 'artist', mbid: string, inc?: ArtistIncludes[]): Promise<mb.IArtist>;
93
+ lookup(entity: 'collection', mbid: string, inc?: CollectionIncludes[]): Promise<mb.ICollection>;
94
+ lookup(entity: 'instrument', mbid: string, inc?: InstrumentIncludes[]): Promise<mb.IInstrument>;
95
+ lookup(entity: 'label', mbid: string, inc?: LabelIncludes[]): Promise<mb.ILabel>;
96
+ lookup(entity: 'place', mbid: string, inc?: PlaceIncludes[]): Promise<mb.IPlace>;
97
+ lookup(entity: 'release', mbid: string, inc?: ReleaseIncludes[]): Promise<mb.IRelease>;
98
+ lookup(entity: 'release-group', mbid: string, inc?: ReleaseGroupIncludes[]): Promise<mb.IReleaseGroup>;
99
+ lookup(entity: 'recording', mbid: string, inc?: RecordingIncludes[]): Promise<mb.IRecording>;
100
+ lookup(entity: 'series', mbid: string, inc?: SeriesIncludes[]): Promise<mb.ISeries>;
101
+ lookup(entity: 'work', mbid: string, inc?: WorkIncludes[]): Promise<mb.IWork>;
102
+ lookup(entity: 'url', mbid: string, inc?: UrlIncludes[]): Promise<mb.IUrl>;
103
+ lookup(entity: 'event', mbid: string, inc?: EventIncludes[]): Promise<mb.IEvent>;
104
+ /**
105
+ * Browse entity
106
+ * https://wiki.musicbrainz.org/MusicBrainz_API#Browse
107
+ * https://wiki.musicbrainz.org/MusicBrainz_API#Linked_entities
171
108
  * https://wiki.musicbrainz.org/Development/JSON_Web_Service#Browse_Requests
109
+ * For example: http://musicbrainz.org/ws/2/release?label=47e718e1-7ee4-460c-b1cc-1192a841c6e5&offset=12&limit=2
172
110
  * @param entity MusicBrainz entity
173
111
  * @param query Query, like: {<entity>: <MBID:}
174
112
  */
175
- browseEntity<T>(entity: mb.EntityType, query?: {
176
- [key: string]: any;
177
- }): Promise<T>;
178
- /**
179
- * Browse areas
180
- * @param query Query, like: {<entity>: <MBID:}
181
- */
182
- browseAreas(query?: mb.IBrowseAreasQuery): Promise<mb.IBrowseAreasResult>;
183
- /**
184
- * Browse artists
185
- * @param query Query, like: {<entity>: <MBID:}
186
- */
187
- browseArtists(query?: mb.IBrowseArtistsQuery): Promise<mb.IBrowseArtistsResult>;
188
- /**
189
- * Browse collections
190
- * @param query Query, like: {<entity>: <MBID:}
191
- */
192
- browseCollections(query?: mb.IBrowseCollectionsQuery): Promise<mb.IBrowseCollectionsResult>;
193
- /**
194
- * Browse events
195
- * @param query Query, like: {<entity>: <MBID:}
196
- */
197
- browseEvents(query?: mb.IBrowseEventsQuery): Promise<mb.IBrowseEventsResult>;
198
- /**
199
- * Browse instruments
200
- * @param query Query, like: {<entity>: <MBID:}
201
- */
202
- browseInstruments(query?: mb.IBrowseInstrumentsQuery): Promise<mb.IBrowseInstrumentsResult>;
203
- /**
204
- * Browse labels
205
- * @param query Query, like: {<entity>: <MBID:}
206
- */
207
- browseLabels(query?: mb.IBrowseLabelsQuery): Promise<mb.IBrowseLabelsResult>;
208
- /**
209
- * Browse places
210
- * @param query Query, like: {<entity>: <MBID:}
211
- */
212
- browsePlaces(query?: mb.IBrowsePlacesQuery): Promise<mb.IBrowsePlacesResult>;
213
- /**
214
- * Browse recordings
215
- * @param query Query, like: {<entity>: <MBID:}
216
- */
217
- browseRecordings(query?: mb.IBrowseRecordingsQuery): Promise<mb.IBrowseRecordingsResult>;
218
- /**
219
- * Browse releases
220
- * @param query Query, like: {<entity>: <MBID:}
221
- */
222
- browseReleases(query?: mb.IBrowseReleasesQuery): Promise<mb.IBrowseReleasesResult>;
223
- /**
224
- * Browse release-groups
225
- * @param query Query, like: {<entity>: <MBID:}
226
- */
227
- browseReleaseGroups(query?: mb.IReleaseGroupsQuery): Promise<mb.IBrowseReleaseGroupsResult>;
228
- /**
229
- * Browse series
230
- * @param query Query, like: {<entity>: <MBID:}
231
- */
232
- browseSeries(query?: mb.IBrowseSeriesQuery): Promise<mb.IBrowseSeriesResult>;
113
+ browse(entity: 'area', query?: mb.IBrowseAreasQuery): Promise<mb.IBrowseAreasResult>;
114
+ browse(entity: 'artist', query?: mb.IBrowseArtistsQuery): Promise<mb.IBrowseArtistsResult>;
115
+ browse(entity: 'collection', query?: mb.IBrowseCollectionsQuery): Promise<mb.IBrowseCollectionsResult>;
116
+ browse(entity: 'event', query?: mb.IBrowseEventsQuery): Promise<mb.IBrowseEventsResult>;
117
+ browse(entity: 'label', query?: mb.IBrowseLabelsQuery): Promise<mb.IBrowseLabelsResult>;
118
+ browse(entity: 'instrument', query?: mb.IBrowseInstrumentsQuery): Promise<mb.IBrowseInstrumentsResult>;
119
+ browse(entity: 'place', query?: mb.IBrowsePlacesQuery): Promise<mb.IBrowsePlacesResult>;
120
+ browse(entity: 'recording', query?: mb.IBrowseRecordingsQuery): Promise<mb.IBrowseRecordingsResult>;
121
+ browse(entity: 'release', query?: mb.IBrowseReleasesQuery): Promise<mb.IBrowseReleasesResult>;
122
+ browse(entity: 'release-group', query?: mb.IBrowseReleaseGroupsQuery): Promise<mb.IBrowseReleaseGroupsResult>;
123
+ browse(entity: 'series', query?: mb.IBrowseSeriesQuery): Promise<mb.IBrowseSeriesResult>;
124
+ browse(entity: 'url', query?: mb.IBrowseUrlsQuery): Promise<mb.IUrl>;
125
+ browse(entity: 'work', query?: mb.IBrowseWorksQuery): Promise<mb.IBrowseWorksResult>;
233
126
  /**
234
- * Browse works
235
- * @param query Query, like: {<entity>: <MBID:}
236
- */
237
- browseWorks(query?: mb.IBrowseWorksQuery): Promise<mb.IBrowseWorksResult>;
238
- /**
239
- * Browse URLs
240
- * @param query Query, like: {<entity>: <MBID:}
127
+ * Search an entity using a search query
128
+ * @param query e.g.: '" artist: Madonna, track: Like a virgin"' or object with search terms: {artist: Madonna}
129
+ * @param entity e.g. 'recording'
130
+ * @param query Arguments
241
131
  */
242
- browseUrls(query?: mb.IBrowseUrlsQuery): Promise<mb.IUrl>;
132
+ search(entity: 'area', query: mb.ISearchQuery<AreaIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IAreaList>;
133
+ search(artist: 'artist', query: mb.ISearchQuery<ArtistIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IArtistList>;
134
+ search(artist: 'recording', query: mb.ISearchQuery<AreaIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IRecordingList>;
135
+ search(artist: 'release', query: mb.ISearchQuery<ReleaseIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IReleaseList>;
136
+ search(artist: 'release-group', query: mb.ISearchQuery<ReleaseGroupIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IReleaseGroupList>;
137
+ search(artist: 'url', query: mb.ISearchQuery<UrlIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IUrlList>;
243
138
  postRecording(xmlMetadata: XmlMetadata): Promise<void>;
244
139
  post(entity: mb.EntityType, xmlMetadata: XmlMetadata): Promise<void>;
245
140
  login(): Promise<boolean>;
@@ -268,16 +163,8 @@ export declare class MusicBrainzApi {
268
163
  * Add ISRC to recording
269
164
  * @param recording Recording to update
270
165
  * @param isrc ISRC code to add
271
- * @param editNote Edit note
272
- */
273
- addIsrc(recording: mb.IRecording, isrc: string, editNote?: string): Promise<void>;
274
- /**
275
- * Search an entity using a search query
276
- * @param query e.g.: '" artist: Madonna, track: Like a virgin"' or object with search terms: {artist: Madonna}
277
- * @param entity e.g. 'recording'
278
- * @param query Arguments
279
166
  */
280
- search<T extends mb.ISearchResult, I extends string = never>(entity: mb.EntityType, query: mb.ISearchQuery<I>): Promise<T>;
167
+ addIsrc(recording: mb.IRecording, isrc: string): Promise<void>;
281
168
  /**
282
169
  * Add Spotify-ID to MusicBrainz recording.
283
170
  * This function will automatically lookup the recording title, which is required to submit the recording URL
@@ -286,11 +173,6 @@ export declare class MusicBrainzApi {
286
173
  * @param editNote Comment to add.
287
174
  */
288
175
  addSpotifyIdToRecording(recording: mb.IRecording, spotifyId: string, editNote: string): Promise<void>;
289
- searchArea(query: mb.ISearchQuery<AreaIncludes> & mb.ILinkedEntitiesArea): Promise<mb.IAreaList>;
290
- searchArtist(query: mb.ISearchQuery<ArtistIncludes> & mb.ILinkedEntitiesArtist): Promise<mb.IArtistList>;
291
- searchRelease(query: mb.ISearchQuery<ReleasesIncludes> & mb.ILinkedEntitiesRelease): Promise<mb.IReleaseList>;
292
- searchReleaseGroup(query: mb.ISearchQuery<ReleaseGroupIncludes> & mb.ILinkedEntitiesReleaseGroup): Promise<mb.IReleaseGroupList>;
293
- searchUrl(query: mb.ISearchQuery<UrlIncludes> & mb.ILinkedEntitiesUrl): Promise<mb.IUrlList>;
294
176
  private getSession;
295
177
  }
296
178
  export declare function makeAndQueryString(keyValuePairs: IFormData): string;
@@ -6,7 +6,7 @@ export { XmlIsrc } from './xml/xml-isrc.js';
6
6
  export { XmlIsrcList } from './xml/xml-isrc-list.js';
7
7
  export { XmlRecording } from './xml/xml-recording.js';
8
8
  import { DigestAuth } from './digest-auth.js';
9
- import { RateLimiter } from './rate-limiter.js';
9
+ import { RateLimitThreshold } from 'rate-limit-threshold';
10
10
  import * as mb from './musicbrainz.types.js';
11
11
  import got from 'got';
12
12
  import { CookieJar } from 'tough-cookie';
@@ -14,35 +14,6 @@ export * from './musicbrainz.types.js';
14
14
  import { promisify } from 'util';
15
15
  const debug = Debug('musicbrainz-api');
16
16
  export class MusicBrainzApi {
17
- static escapeText(text) {
18
- let str = '';
19
- for (const chr of text) {
20
- // Escaping Special Characters: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ /
21
- // ToDo: && ||
22
- switch (chr) {
23
- case '+':
24
- case '-':
25
- case '!':
26
- case '(':
27
- case ')':
28
- case '{':
29
- case '}':
30
- case '[':
31
- case ']':
32
- case '^':
33
- case '"':
34
- case '~':
35
- case '*':
36
- case '?':
37
- case ':':
38
- case '\\':
39
- case '/':
40
- str += '\\';
41
- }
42
- str += chr;
43
- }
44
- return str;
45
- }
46
17
  static fetchCsrf(html) {
47
18
  return {
48
19
  sessionKey: MusicBrainzApi.fetchValue(html, 'csrf_session_key'),
@@ -56,15 +27,13 @@ export class MusicBrainzApi {
56
27
  if (pos >= 0) {
57
28
  pos += 7;
58
29
  const endValuePos = html.indexOf('"', pos);
59
- const value = html.substring(pos, endValuePos);
60
- return value;
30
+ return html.substring(pos, endValuePos);
61
31
  }
62
32
  }
63
33
  }
64
34
  constructor(_config) {
65
35
  this.config = {
66
- baseUrl: 'https://musicbrainz.org',
67
- botAccount: {}
36
+ baseUrl: 'https://musicbrainz.org'
68
37
  };
69
38
  Object.assign(this.config, _config);
70
39
  const cookieJar = new CookieJar();
@@ -80,11 +49,12 @@ export class MusicBrainzApi {
80
49
  },
81
50
  cookieJar: cookieJar
82
51
  };
83
- this.rateLimiter = new RateLimiter(15, 18);
52
+ this.rateLimiter = new RateLimitThreshold(15, 18);
84
53
  }
85
- async restGet(relUrl, query = {}, attempt = 1) {
54
+ async restGet(relUrl, query = {}) {
86
55
  query.fmt = 'json';
87
- await this.rateLimiter.limit();
56
+ const delay = await this.rateLimiter.limit();
57
+ debug(`Client side rate limiter activated: cool down for ${Math.round(delay / 100) / 10} s...`);
88
58
  const response = await got.get('ws/2' + relUrl, {
89
59
  ...this.options,
90
60
  searchParams: query,
@@ -95,225 +65,21 @@ export class MusicBrainzApi {
95
65
  });
96
66
  return response.body;
97
67
  }
98
- // -----------------------------------------------------------------------------------------------------------------
99
- // Lookup functions
100
- // -----------------------------------------------------------------------------------------------------------------
101
- /**
102
- * Generic lookup function
103
- * @param entity
104
- * @param mbid
105
- * @param inc
106
- */
107
- lookupEntity(entity, mbid, inc = []) {
68
+ lookup(entity, mbid, inc = []) {
108
69
  return this.restGet(`/${entity}/${mbid}`, { inc: inc.join(' ') });
109
70
  }
110
- /**
111
- * Lookup area
112
- * @param areaId Area MBID
113
- * @param inc Sub-queries
114
- */
115
- lookupArea(areaId, inc = []) {
116
- return this.lookupEntity('area', areaId, inc);
117
- }
118
- /**
119
- * Lookup artist
120
- * @param artistId Artist MBID
121
- * @param inc Sub-queries
122
- */
123
- lookupArtist(artistId, inc = []) {
124
- return this.lookupEntity('artist', artistId, inc);
125
- }
126
- /**
127
- * Lookup collection
128
- * @param collectionId Collection MBID
129
- * @param inc List of additional information to be included about the entity. Any of the entities directly linked to the entity can be included.
130
- */
131
- lookupCollection(collectionId, inc = []) {
132
- return this.lookupEntity('collection', collectionId, inc);
133
- }
134
- /**
135
- * Lookup instrument
136
- * @param artistId Instrument MBID
137
- * @param inc Sub-queries
138
- */
139
- lookupInstrument(instrumentId, inc = []) {
140
- return this.lookupEntity('instrument', instrumentId, inc);
141
- }
142
- /**
143
- * Lookup label
144
- * @param labelId Area MBID
145
- * @param inc Sub-queries
146
- */
147
- lookupLabel(labelId, inc = []) {
148
- return this.lookupEntity('label', labelId, inc);
149
- }
150
- /**
151
- * Lookup place
152
- * @param placeId Area MBID
153
- * @param inc Sub-queries
154
- */
155
- lookupPlace(placeId, inc = []) {
156
- return this.lookupEntity('place', placeId, inc);
157
- }
158
- /**
159
- * Lookup release
160
- * @param releaseId Release MBID
161
- * @param inc Include: artist-credits, labels, recordings, release-groups, media, discids, isrcs (with recordings)
162
- * ToDo: ['recordings', 'artists', 'artist-credits', 'isrcs', 'url-rels', 'release-groups']
163
- */
164
- lookupRelease(releaseId, inc = []) {
165
- return this.lookupEntity('release', releaseId, inc);
166
- }
167
- /**
168
- * Lookup release-group
169
- * @param releaseGroupId Release-group MBID
170
- * @param inc Include: ToDo
171
- */
172
- lookupReleaseGroup(releaseGroupId, inc = []) {
173
- return this.lookupEntity('release-group', releaseGroupId, inc);
174
- }
175
- /**
176
- * Lookup recording
177
- * @param recordingId Label MBID
178
- * @param inc Include: artist-credits, isrcs
179
- */
180
- lookupRecording(recordingId, inc = []) {
181
- return this.lookupEntity('recording', recordingId, inc);
182
- }
183
- /**
184
- * Lookup series
185
- * @param seriesId Series MBID
186
- */
187
- lookupSeries(seriesId) {
188
- return this.lookupEntity('series', seriesId);
189
- }
190
- /**
191
- * Lookup work
192
- * @param workId Work MBID
193
- */
194
- lookupWork(workId, inc = []) {
195
- return this.lookupEntity('work', workId, inc);
196
- }
197
- /**
198
- * Lookup URL
199
- * @param urlId URL MBID
200
- */
201
- lookupUrl(urlId, inc = []) {
202
- return this.lookupEntity('url', urlId, inc);
203
- }
204
- /**
205
- * Lookup Event
206
- * @param eventId Event MBID
207
- * @param eventIncludes List of sub-queries to enable
208
- */
209
- lookupEvent(eventId, eventIncludes = []) {
210
- return this.lookupEntity('event', eventId, eventIncludes);
211
- }
212
- // -----------------------------------------------------------------------------------------------------------------
213
- // Browse functions
214
- // -----------------------------------------------------------------------------------------------------------------
215
- // https://wiki.musicbrainz.org/MusicBrainz_API#Browse
216
- // https://wiki.musicbrainz.org/MusicBrainz_API#Linked_entities
217
- // For example: http://musicbrainz.org/ws/2/release?label=47e718e1-7ee4-460c-b1cc-1192a841c6e5&offset=12&limit=2
218
- /**
219
- * Generic browse function
220
- * https://wiki.musicbrainz.org/Development/JSON_Web_Service#Browse_Requests
221
- * @param entity MusicBrainz entity
222
- * @param query Query, like: {<entity>: <MBID:}
223
- */
224
- browseEntity(entity, query) {
71
+ browse(entity, query) {
225
72
  return this.restGet(`/${entity}`, query);
226
73
  }
227
- /**
228
- * Browse areas
229
- * @param query Query, like: {<entity>: <MBID:}
230
- */
231
- browseAreas(query) {
232
- return this.browseEntity('area', query);
233
- }
234
- /**
235
- * Browse artists
236
- * @param query Query, like: {<entity>: <MBID:}
237
- */
238
- browseArtists(query) {
239
- return this.browseEntity('artist', query);
240
- }
241
- /**
242
- * Browse collections
243
- * @param query Query, like: {<entity>: <MBID:}
244
- */
245
- browseCollections(query) {
246
- return this.browseEntity('collection', query);
247
- }
248
- /**
249
- * Browse events
250
- * @param query Query, like: {<entity>: <MBID:}
251
- */
252
- browseEvents(query) {
253
- return this.browseEntity('event', query);
254
- }
255
- /**
256
- * Browse instruments
257
- * @param query Query, like: {<entity>: <MBID:}
258
- */
259
- browseInstruments(query) {
260
- return this.browseEntity('instrument', query);
261
- }
262
- /**
263
- * Browse labels
264
- * @param query Query, like: {<entity>: <MBID:}
265
- */
266
- browseLabels(query) {
267
- return this.browseEntity('label', query);
268
- }
269
- /**
270
- * Browse places
271
- * @param query Query, like: {<entity>: <MBID:}
272
- */
273
- browsePlaces(query) {
274
- return this.browseEntity('place', query);
275
- }
276
- /**
277
- * Browse recordings
278
- * @param query Query, like: {<entity>: <MBID:}
279
- */
280
- browseRecordings(query) {
281
- return this.browseEntity('recording', query);
282
- }
283
- /**
284
- * Browse releases
285
- * @param query Query, like: {<entity>: <MBID:}
286
- */
287
- browseReleases(query) {
288
- return this.browseEntity('release', query);
289
- }
290
- /**
291
- * Browse release-groups
292
- * @param query Query, like: {<entity>: <MBID:}
293
- */
294
- browseReleaseGroups(query) {
295
- return this.browseEntity('release-group', query);
296
- }
297
- /**
298
- * Browse series
299
- * @param query Query, like: {<entity>: <MBID:}
300
- */
301
- browseSeries(query) {
302
- return this.browseEntity('series', query);
303
- }
304
- /**
305
- * Browse works
306
- * @param query Query, like: {<entity>: <MBID:}
307
- */
308
- browseWorks(query) {
309
- return this.browseEntity('work', query);
310
- }
311
- /**
312
- * Browse URLs
313
- * @param query Query, like: {<entity>: <MBID:}
314
- */
315
- browseUrls(query) {
316
- return this.browseEntity('url', query);
74
+ search(entity, query) {
75
+ const urlQuery = { ...query };
76
+ if (typeof query.query === 'object') {
77
+ urlQuery.query = makeAndQueryString(query.query);
78
+ }
79
+ if (Array.isArray(query.inc)) {
80
+ urlQuery.inc = urlQuery.inc.join(' ');
81
+ }
82
+ return this.restGet('/' + entity + '/', urlQuery);
317
83
  }
318
84
  // ---------------------------------------------------------------------------
319
85
  async postRecording(xmlMetadata) {
@@ -354,8 +120,9 @@ export class MusicBrainzApi {
354
120
  } while (n++ < 5);
355
121
  }
356
122
  async login() {
357
- assert.ok(this.config.botAccount.username, 'bot username should be set');
358
- assert.ok(this.config.botAccount.password, 'bot password should be set');
123
+ var _a, _b;
124
+ assert.ok((_a = this.config.botAccount) === null || _a === void 0 ? void 0 : _a.username, 'bot username should be set');
125
+ assert.ok((_b = this.config.botAccount) === null || _b === void 0 ? void 0 : _b.password, 'bot password should be set');
359
126
  if (this.session && this.session.loggedIn) {
360
127
  for (const cookie of await this.getCookies(this.options.prefixUrl)) {
361
128
  if (cookie.key === 'remember_login') {
@@ -411,12 +178,13 @@ export class MusicBrainzApi {
411
178
  * @param formData
412
179
  */
413
180
  async editEntity(entity, mbid, formData) {
181
+ var _a, _b;
414
182
  await this.rateLimiter.limit();
415
183
  this.session = await this.getSession();
416
184
  formData.csrf_session_key = this.session.csrf.sessionKey;
417
185
  formData.csrf_token = this.session.csrf.token;
418
- formData.username = this.config.botAccount.username;
419
- formData.password = this.config.botAccount.password;
186
+ formData.username = (_a = this.config.botAccount) === null || _a === void 0 ? void 0 : _a.username;
187
+ formData.password = (_b = this.config.botAccount) === null || _b === void 0 ? void 0 : _b.password;
420
188
  formData.remember_me = 1;
421
189
  const response = await got.post(`${entity}/${mbid}/edit`, {
422
190
  ...this.options,
@@ -453,9 +221,8 @@ export class MusicBrainzApi {
453
221
  * Add ISRC to recording
454
222
  * @param recording Recording to update
455
223
  * @param isrc ISRC code to add
456
- * @param editNote Edit note
457
224
  */
458
- async addIsrc(recording, isrc, editNote = '') {
225
+ async addIsrc(recording, isrc) {
459
226
  const formData = {};
460
227
  formData[`edit-recording.name`] = recording.title; // Required
461
228
  if (!recording.isrcs) {
@@ -470,25 +237,6 @@ export class MusicBrainzApi {
470
237
  }
471
238
  }
472
239
  // -----------------------------------------------------------------------------------------------------------------
473
- // Query functions
474
- // -----------------------------------------------------------------------------------------------------------------
475
- /**
476
- * Search an entity using a search query
477
- * @param query e.g.: '" artist: Madonna, track: Like a virgin"' or object with search terms: {artist: Madonna}
478
- * @param entity e.g. 'recording'
479
- * @param query Arguments
480
- */
481
- search(entity, query) {
482
- const urlQuery = { ...query };
483
- if (typeof query.query === 'object') {
484
- urlQuery.query = makeAndQueryString(query.query);
485
- }
486
- if (Array.isArray(query.inc)) {
487
- urlQuery.inc = urlQuery.inc.join(' ');
488
- }
489
- return this.restGet('/' + entity + '/', urlQuery);
490
- }
491
- // -----------------------------------------------------------------------------------------------------------------
492
240
  // Helper functions
493
241
  // -----------------------------------------------------------------------------------------------------------------
494
242
  /**
@@ -505,25 +253,10 @@ export class MusicBrainzApi {
505
253
  text: 'https://open.spotify.com/track/' + spotifyId
506
254
  }, editNote);
507
255
  }
508
- searchArea(query) {
509
- return this.search('area', query);
510
- }
511
- searchArtist(query) {
512
- return this.search('artist', query);
513
- }
514
- searchRelease(query) {
515
- return this.search('release', query);
516
- }
517
- searchReleaseGroup(query) {
518
- return this.search('release-group', query);
519
- }
520
- searchUrl(query) {
521
- return this.search('url', query);
522
- }
523
256
  async getSession() {
524
257
  const response = await got.get('login', {
525
258
  ...this.options,
526
- followRedirect: false,
259
+ followRedirect: false, // Disable redirects
527
260
  responseType: 'text'
528
261
  });
529
262
  return {
@@ -104,6 +104,7 @@ export interface IRelease extends IEntity {
104
104
  relations?: IRelation[];
105
105
  'artist-credit'?: IArtistCredit[];
106
106
  'release-group'?: IReleaseGroup;
107
+ collections?: ICollection[];
107
108
  }
108
109
  export interface IReleaseEvent {
109
110
  area?: IArea;
@@ -162,14 +163,16 @@ export interface IReleaseGroup extends IEntity {
162
163
  }[];
163
164
  releases?: IRelease[];
164
165
  }
166
+ export interface IAreaMatch extends IArea, IMatch {
167
+ }
165
168
  export interface IArtistMatch extends IArtist, IMatch {
166
169
  }
170
+ export interface IRecordingMatch extends IRecording, IMatch {
171
+ }
167
172
  export interface IReleaseGroupMatch extends IReleaseGroup, IMatch {
168
173
  }
169
174
  export interface IReleaseMatch extends IRelease, IMatch {
170
175
  }
171
- export interface IAreaMatch extends IArea, IMatch {
172
- }
173
176
  export interface ISearchResult {
174
177
  created: DateTimeFormat;
175
178
  count: number;
@@ -185,6 +188,10 @@ export interface IReleaseList extends ISearchResult {
185
188
  releases: IReleaseMatch[];
186
189
  'release-count': number;
187
190
  }
191
+ export interface IRecordingList extends ISearchResult {
192
+ recordings: IRecordingMatch[];
193
+ 'recordings-count': number;
194
+ }
188
195
  export interface IReleaseGroupList extends ISearchResult {
189
196
  'release-groups': IReleaseGroupMatch[];
190
197
  }
@@ -285,6 +292,7 @@ export interface ISearchQuery<I extends string> extends IPagination {
285
292
  */
286
293
  query?: string | IFormData;
287
294
  inc?: I[];
295
+ artist?: string;
288
296
  }
289
297
  /**
290
298
  * https://musicbrainz.org/doc/MusicBrainz_API#Browse
@@ -508,7 +516,7 @@ export interface IBrowseReleasesQuery extends IPagination {
508
516
  /**
509
517
  * Browse release-groups query <entity>: <MBID>
510
518
  */
511
- export interface IReleaseGroupsQuery extends IPagination {
519
+ export interface IBrowseReleaseGroupsQuery extends IPagination {
512
520
  artist?: string;
513
521
  collection?: string;
514
522
  release?: string;
@@ -586,12 +594,12 @@ export interface IBrowseReleaseGroupsResult {
586
594
  'release-group-offset': number;
587
595
  }
588
596
  export interface IBrowseSeriesResult {
589
- series: IReleaseGroupsQuery[];
597
+ series: IReleaseGroup[];
590
598
  'series-count': number;
591
599
  'series-offset': number;
592
600
  }
593
601
  export interface IBrowseWorksResult {
594
- works: IReleaseGroupsQuery[];
602
+ works: IReleaseGroup[];
595
603
  'work-count': number;
596
604
  'work-offset': number;
597
605
  }
@@ -10,5 +10,5 @@ export var LinkType;
10
10
  LinkType[LinkType["crowdfunding_page"] = 905] = "crowdfunding_page";
11
11
  LinkType[LinkType["other_databases"] = 306] = "other_databases";
12
12
  LinkType[LinkType["Allmusic"] = 285] = "Allmusic";
13
- })(LinkType = LinkType || (LinkType = {}));
13
+ })(LinkType || (LinkType = {}));
14
14
  //# sourceMappingURL=musicbrainz.types.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musicbrainz-api",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "MusicBrainz API client for reading and submitting metadata",
5
5
  "exports": "./lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -34,7 +34,6 @@
34
34
  "download covers"
35
35
  ],
36
36
  "license": "MIT",
37
- "private": false,
38
37
  "engines": {
39
38
  "node": "^14.13.1 || >=16.0.0"
40
39
  },
@@ -51,10 +50,11 @@
51
50
  "@types/uuid": "^9.0.0",
52
51
  "caseless": "^0.12.0",
53
52
  "debug": "^4.3.4",
54
- "got": "^13.0.0",
53
+ "got": "^14.2.1",
55
54
  "http-status-codes": "^2.1.4",
56
55
  "json-stringify-safe": "^5.0.1",
57
56
  "jsontoxml": "^1.0.1",
57
+ "rate-limit-threshold": "^0.1.5",
58
58
  "source-map-support": "^0.5.16",
59
59
  "tough-cookie": "^4.1.3",
60
60
  "uuid": "^9.0.0"
@@ -62,25 +62,24 @@
62
62
  "devDependencies": {
63
63
  "@types/chai": "^4.3.0",
64
64
  "@types/jsontoxml": "^1.0.5",
65
- "@types/mocha": "^9.0.0",
65
+ "@types/mocha": "^10.0.4",
66
66
  "@types/node": "^20.8.10",
67
67
  "@typescript-eslint/eslint-plugin": "^5.13.0",
68
68
  "@typescript-eslint/parser": "^5.13.0",
69
- "c8": "^8.0.1",
70
- "chai": "^4.2.0",
69
+ "c8": "^9.1.0",
70
+ "chai": "^5.1.0",
71
71
  "del-cli": "^5.0.0",
72
72
  "eslint": "^8.10.0",
73
- "eslint-config-prettier": "^8.4.0",
73
+ "eslint-config-prettier": "^9.0.0",
74
74
  "eslint-import-resolver-typescript": "^3.3.0",
75
75
  "eslint-plugin-import": "^2.25.4",
76
- "eslint-plugin-jsdoc": "^46.8.2",
76
+ "eslint-plugin-jsdoc": "^48.2.2",
77
77
  "eslint-plugin-node": "^11.1.0",
78
- "eslint-plugin-unicorn": "^46.0.0",
78
+ "eslint-plugin-unicorn": "^49.0.0",
79
79
  "mocha": "^10.1.0",
80
- "remark-cli": "^11.0.0",
80
+ "remark-cli": "^12.0.0",
81
81
  "remark-preset-lint-recommended": "^6.1.2",
82
82
  "ts-node": "^10.0.0",
83
- "tslint": "^6.1.1",
84
83
  "typescript": "^5.0.2"
85
84
  },
86
85
  "scripts": {
@@ -111,5 +110,6 @@
111
110
  "text"
112
111
  ],
113
112
  "report-dir": "coverage"
114
- }
113
+ },
114
+ "packageManager": "yarn@4.1.1"
115
115
  }
@@ -1,8 +0,0 @@
1
- export declare class RateLimiter {
2
- private maxCalls;
3
- static sleep(ms: number): Promise<void>;
4
- queue: number[];
5
- private readonly period;
6
- constructor(maxCalls: number, period: number);
7
- limit(): Promise<void>;
8
- }
@@ -1,30 +0,0 @@
1
- import Debug from 'debug';
2
- const debug = Debug('musicbrainz-api:rate-limiter');
3
- export class RateLimiter {
4
- static sleep(ms) {
5
- return new Promise(resolve => setTimeout(resolve, ms));
6
- }
7
- constructor(maxCalls, period) {
8
- this.maxCalls = maxCalls;
9
- this.queue = [];
10
- debug(`Rate limiter initialized with max ${maxCalls} calls in ${period} seconds.`);
11
- this.period = 1000 * period;
12
- }
13
- async limit() {
14
- let now = new Date().getTime();
15
- const t0 = now - (this.period);
16
- while (this.queue.length > 0 && this.queue[0] < t0) {
17
- this.queue.shift();
18
- }
19
- // debug(`Current rate is ${this.queue.length} per ${this.period / 1000} sec`);
20
- if (this.queue.length >= this.maxCalls) {
21
- const delay = this.queue[0] + this.period - now;
22
- debug(`Client side rate limiter activated: cool down for ${delay / 1000} s...`);
23
- return RateLimiter.sleep(delay);
24
- }
25
- now = new Date().getTime();
26
- this.queue.push(now);
27
- // const ratePerSec = 1000 * this.queue.length / (now - this.queue[0]);
28
- }
29
- }
30
- //# sourceMappingURL=rate-limiter.js.map