musicbrainz-api 0.22.0 → 0.23.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
@@ -116,18 +116,34 @@ MusicBrainz API documentation: [XML Web Service/Version 2 Lookups](https://wiki.
116
116
  ### Lookup Function
117
117
 
118
118
  ```js
119
- const artist = await mbApi.lookup('artist', 'ab2528d9-719f-4261-8098-21849222a0f2');
119
+ const artist = await mbApi.lookup('artist', 'ab2528d9-719f-4261-8098-21849222a0f2', ['recordings']);
120
120
  ```
121
121
 
122
122
  Arguments:
123
- - entity: `'area'` | `'artist'` | `'collection'` | `'instrument'` | `'label'` | `'place'` | `'release'` | `'release-group'` | `'recording'` | `'series'` | `'work'` | `'url'` | `'event'`
124
- - MBID [(MusicBrainz identifier)](https://wiki.musicbrainz.org/MusicBrainz_Identifier)
125
- - query
123
+ - entity (`string`): `'area'` | `'artist'` | `'collection'` | `'instrument'` | `'label'` | `'place'` | `'release'` | `'release-group'` | `'recording'` | `'series'` | `'work'` | `'url'` | `'event'`
124
+ - MBID (`string`): [(MusicBrainz identifier)](https://wiki.musicbrainz.org/MusicBrainz_Identifier)
125
+ - include arguments (`string[]`), see [Include arguments](#include-arguments)
126
126
 
127
+ #### Lookup URLs
127
128
 
128
- | Query argument | Query value |
129
- |-----------------------|-----------------|
130
- | `query.collection` | Collection MBID |
129
+ There is special method to lookup URL entity / entities by one, or an array of URLs
130
+ ([MusicBrainz documentation](https://musicbrainz.org/doc/MusicBrainz_API#url_(by_text))):
131
+
132
+ ```js
133
+ const urls = await mbApi.lookupUrl(['https://open.spotify.com/track/2AMysGXOe0zzZJMtH3Nizb', 'https://open.spotify.com/track/78Teboqh9lPIxWlIW5RMQL']);
134
+ ```
135
+
136
+ or
137
+
138
+ ```js
139
+ const url = await mbApi.lookupUrl('https://open.spotify.com/track/2AMysGXOe0zzZJMtH3Nizb']);
140
+ ```
141
+
142
+ Arguments:
143
+ - url (`string` | `string[]`): URL or array of URLs
144
+ - include arguments (`string[]`), see [Include arguments](#include-arguments)
145
+
146
+ Note that the return type is different, depending on if a single URL or an array of URLs is provided.
131
147
 
132
148
  ### Browse artist
133
149
 
@@ -355,6 +371,82 @@ Search a combination of a release-group and an artist.
355
371
  const result = await mbApi.search('release-group', {artist: 'Racine carrée', releasegroup: 'Stromae'});
356
372
  ```
357
373
 
374
+ ## Include arguments
375
+
376
+
377
+ ### Subqueries
378
+
379
+ _Include Arguments_ which allow you to request more information to be included about the entity.
380
+
381
+ | entity | supported _include arguments_ |
382
+ |------------------|----------------------------------------------------------------------------|
383
+ | `area` | |
384
+ | `artist` | `recordings`, `releases`, `release-groups`, `works` |
385
+ | `collection` | `user-collections` (includes private collections, requires authentication) |
386
+ | `event` | |
387
+ | `genre` | |
388
+ | `instrument` | |
389
+ | `label` | `releases` |
390
+ | `place` | |
391
+ | `recording` | `artists`, `releases`, `release-groups`, `isrcs`, `url-rels` |
392
+ | `release` | `artists`, `collections`, `labels`, `recordings`, `release-groups` |
393
+ | `release-group` | `artists`, `releases` |
394
+ | `series` | |
395
+ | `work` | |
396
+ | `url` | |
397
+
398
+ ### Arguments which affect subqueries
399
+
400
+ Some additional _include parameters_ are supported to specify how much of the data about the linked entities should be included:
401
+
402
+ | _include argument_ | Description |
403
+ |--------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
404
+ | `discids` | include discids for all media in the releases |
405
+ | `media` | include media for all releases, this includes the # of tracks on each medium and its format. |
406
+ | `isrcs` | user-collections (includes private collections, requires authentication)include isrcs for all recordings |
407
+ | `artist-credits` | include artists credits for all releases and recordings |
408
+ | `various-artists` | include only those releases where the artist appears on one of the tracks, but not in the artist credit for the release itself (this is only valid on entity `"artist"` and _include argument_ `"releases request"`). |
409
+
410
+ ### Miscellaneous arguments
411
+
412
+ | _include argument_ | Description |
413
+ |-----------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
414
+ | `aliases` | include artist, label, area or work aliases; treat these as a set, as they are not deliberately ordered |
415
+ | `annotation` | include annotation |
416
+ | `tags`, `ratings` | include tags and/or ratings for the entity |
417
+ | `user-tags`, `user-ratings` | same as above, but only return the tags and/or ratings submitted by the specified user |
418
+ | `genres`, `user-genres` | include genres (tags in the [genres list](https://musicbrainz.org/genres)): either all or the ones submitted by the user, respectively |
419
+
420
+ ### Relationships
421
+
422
+ You can request relationships with the appropriate includes:
423
+ - `area-rels`
424
+ - `artist-rels`
425
+ - `event-rels`
426
+ - `genre-rels`
427
+ - `instrument-rels`
428
+ - `label-rels`
429
+ - `place-rels`
430
+ - `recording-rels`
431
+ - `release-rels`
432
+ - `release-group-rels`
433
+ - `series-rels`
434
+ - `url-rels`
435
+ - `work-rels`
436
+
437
+ These will load relationships between the requested entity and the specific entity type.
438
+ For example, if you request "work-rels" when looking up an artist,
439
+ you'll get all the relationships between this artist and any works,
440
+ and if you request "artist-rels" you'll get the relationships between this artist and any other artists.
441
+ As such, keep in mind requesting "artist-rels" for an artist, "release-rels" for a release, etc. will not load all the relationships for the entity, just the ones to other entities of the same type.
442
+
443
+ In a release request, you might also be interested on relationships for the recordings linked to the release, or the release group linked to the release, or even for the works linked to those recordings that are linked to the release (for example, to find out who played guitar on a specific track, who wrote the lyrics for the song being performed, or whether the release group is part of a series). Similarly, for a recording request, you might want to get the relationships for any linked works.
444
+ There are three additional includes for this:
445
+
446
+ - recording-level-rels
447
+ - release-group-level-rels (for releases only)
448
+ - work-level-rels
449
+
358
450
  # Submitting data via XML POST
359
451
 
360
452
  [Submitting data via XML POST](https://wiki.musicbrainz.org/Development/XML_Web_Service/Version_2#Submitting_data) may be done using personal MusicBrainz credentials.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "musicbrainz-api",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "description": "MusicBrainz API client for reading and submitting metadata",
5
5
  "exports": {
6
6
  "node": {
@@ -115,5 +115,5 @@
115
115
  ],
116
116
  "report-dir": "coverage"
117
117
  },
118
- "packageManager": "yarn@4.6.0"
118
+ "packageManager": "yarn@4.9.1"
119
119
  }
@@ -1,74 +0,0 @@
1
- export type CovertType = 'Front' | 'Back' | 'Booklet' | 'Medium' | 'Obi' | 'Spine' | 'Track' | 'Tray' | 'Sticker' | 'Poster' | 'Liner' | 'Watermark' | 'Raw/Unedited' | 'Matrix/Runout' | 'Top' | 'Bottom' | 'Other';
2
- export interface IImage {
3
- types: CovertType[];
4
- front: boolean;
5
- back: boolean;
6
- edit: number;
7
- image: string;
8
- comment: string;
9
- approved: boolean;
10
- id: string;
11
- thumbnails: {
12
- large: string;
13
- small: string;
14
- '250': string;
15
- '500'?: string;
16
- '1200'?: string;
17
- };
18
- }
19
- export type CoverType = 'front' | 'back';
20
- export interface ICoversInfo {
21
- images: IImage[];
22
- release: string;
23
- }
24
- export interface ICoverInfo {
25
- url: string | null;
26
- }
27
- export declare class CoverArtArchiveApi {
28
- private httpClient;
29
- private getJson;
30
- private getCoverRedirect;
31
- /**
32
- * Fetch release
33
- * @releaseId Release MBID
34
- * @param releaseId MusicBrainz Release MBID
35
- */
36
- getReleaseCovers(releaseId: string): Promise<ICoversInfo>;
37
- /**
38
- * Fetch release-group
39
- * @releaseGroupId Release-group MBID
40
- * @param releaseGroupId MusicBrainz Release Group MBID
41
- */
42
- getReleaseGroupCovers(releaseGroupId: string): Promise<ICoversInfo>;
43
- /**
44
- * Fetch release cover
45
- * @releaseId Release MBID
46
- * @param releaseId MusicBrainz Release MBID
47
- * @param coverType Front or back cover
48
- */
49
- getReleaseCover(releaseId: string, coverType: CoverType): Promise<ICoverInfo>;
50
- /**
51
- * Fetch release-group cover
52
- * @releaseId Release-group MBID
53
- * @param releaseGroupId MusicBrainz Release-group MBID
54
- * @param coverType Front or back cover
55
- */
56
- getReleaseGroupCover(releaseGroupId: string, coverType: CoverType): Promise<ICoverInfo>;
57
- private static makePath;
58
- /**
59
- * Fetch covers
60
- * @releaseId MBID
61
- * @param releaseId MusicBrainz Release Group MBID
62
- * @param releaseType Fetch covers for specific release or release-group
63
- * @param coverType Cover type
64
- */
65
- private getCovers;
66
- /**
67
- * Fetch covers
68
- * @releaseId MBID
69
- * @param releaseId MusicBrainz Release Group MBID
70
- * @param releaseType Fetch covers for specific release or release-group
71
- * @param coverType Cover type
72
- */
73
- private getCover;
74
- }
@@ -1,110 +0,0 @@
1
- /* eslint-disable-next-line */
2
- import { HttpClient } from "./http-client.js";
3
- export class CoverArtArchiveApi {
4
- constructor() {
5
- this.httpClient = new HttpClient({ baseUrl: 'https://coverartarchive.org', userAgent: 'Node.js musicbrains-api', timeout: 20000, followRedirects: false });
6
- }
7
- async getJson(path) {
8
- const response = await this.httpClient.get(path, {
9
- headers: {
10
- Accept: "application/json"
11
- }
12
- });
13
- const contentType = response.headers.get("Content-Type");
14
- if (response.status === 404 && contentType?.toLowerCase() !== "application/json") {
15
- return {
16
- "error": "Not Found",
17
- "help": "For usage, please see: https://musicbrainz.org/development/mmd"
18
- };
19
- }
20
- return response.json();
21
- }
22
- async getCoverRedirect(path) {
23
- const response = await this.httpClient.get(path, {
24
- followRedirects: false
25
- });
26
- switch (response.status) {
27
- case 307:
28
- return response.headers.get('LOCATION');
29
- case 400:
30
- throw new Error('Invalid UUID');
31
- case 404:
32
- // No release with this MBID
33
- return null;
34
- case 405:
35
- throw new Error('Invalid HTTP method');
36
- case 503:
37
- return null;
38
- default:
39
- throw new Error(`Unexpected HTTP-status response: ${response.status}`);
40
- }
41
- }
42
- /**
43
- * Fetch release
44
- * @releaseId Release MBID
45
- * @param releaseId MusicBrainz Release MBID
46
- */
47
- getReleaseCovers(releaseId) {
48
- return this.getCovers(releaseId, 'release');
49
- }
50
- /**
51
- * Fetch release-group
52
- * @releaseGroupId Release-group MBID
53
- * @param releaseGroupId MusicBrainz Release Group MBID
54
- */
55
- getReleaseGroupCovers(releaseGroupId) {
56
- return this.getCovers(releaseGroupId, 'release-group');
57
- }
58
- /**
59
- * Fetch release cover
60
- * @releaseId Release MBID
61
- * @param releaseId MusicBrainz Release MBID
62
- * @param coverType Front or back cover
63
- */
64
- getReleaseCover(releaseId, coverType) {
65
- return this.getCover(releaseId, 'release', coverType);
66
- }
67
- /**
68
- * Fetch release-group cover
69
- * @releaseId Release-group MBID
70
- * @param releaseGroupId MusicBrainz Release-group MBID
71
- * @param coverType Front or back cover
72
- */
73
- getReleaseGroupCover(releaseGroupId, coverType) {
74
- return this.getCover(releaseGroupId, 'release-group', coverType);
75
- }
76
- static makePath(releaseId, releaseType = 'release', coverType) {
77
- const path = [releaseType, releaseId];
78
- if (coverType) {
79
- path.push(coverType);
80
- }
81
- return `/${path.join('/')}`;
82
- }
83
- /**
84
- * Fetch covers
85
- * @releaseId MBID
86
- * @param releaseId MusicBrainz Release Group MBID
87
- * @param releaseType Fetch covers for specific release or release-group
88
- * @param coverType Cover type
89
- */
90
- async getCovers(releaseId, releaseType = 'release') {
91
- const info = await this.getJson(CoverArtArchiveApi.makePath(releaseId, releaseType));
92
- // Hack to correct http addresses into https
93
- if (info.release?.startsWith('http:')) {
94
- info.release = `https${info.release.substring(4)}`;
95
- }
96
- return info;
97
- }
98
- /**
99
- * Fetch covers
100
- * @releaseId MBID
101
- * @param releaseId MusicBrainz Release Group MBID
102
- * @param releaseType Fetch covers for specific release or release-group
103
- * @param coverType Cover type
104
- */
105
- async getCover(releaseId, releaseType = 'release', coverType) {
106
- const url = await this.getCoverRedirect(CoverArtArchiveApi.makePath(releaseId, releaseType, coverType));
107
- return { url: url };
108
- }
109
- }
110
- //# sourceMappingURL=coverartarchive-api.js.map
@@ -1,21 +0,0 @@
1
- export interface ICredentials {
2
- username: string;
3
- password: string;
4
- }
5
- export declare class DigestAuth {
6
- private credentials;
7
- /**
8
- * RFC 2617: handle both MD5 and MD5-sess algorithms.
9
- *
10
- * If the algorithm directive's value is "MD5" or unspecified, then HA1 is
11
- * HA1=MD5(username:realm:password)
12
- * If the algorithm directive's value is "MD5-sess", then HA1 is
13
- * HA1=MD5(MD5(username:realm:password):nonce:cnonce)
14
- */
15
- static ha1Compute(algorithm: string, user: string, realm: string, pass: string, nonce: string, cnonce: string): string;
16
- hasAuth: boolean;
17
- sentAuth: boolean;
18
- bearerToken: string | null;
19
- constructor(credentials: ICredentials);
20
- digest(method: string, path: string, authHeader: string): string;
21
- }
@@ -1,77 +0,0 @@
1
- import { v4 as uuidv4 } from 'uuid';
2
- import sparkMd5 from 'spark-md5';
3
- const md5 = sparkMd5.hash;
4
- export class DigestAuth {
5
- /**
6
- * RFC 2617: handle both MD5 and MD5-sess algorithms.
7
- *
8
- * If the algorithm directive's value is "MD5" or unspecified, then HA1 is
9
- * HA1=MD5(username:realm:password)
10
- * If the algorithm directive's value is "MD5-sess", then HA1 is
11
- * HA1=MD5(MD5(username:realm:password):nonce:cnonce)
12
- */
13
- static ha1Compute(algorithm, user, realm, pass, nonce, cnonce) {
14
- const ha1 = md5(`${user}:${realm}:${pass}`); // lgtm [js/insufficient-password-hash]
15
- return algorithm && algorithm.toLowerCase() === 'md5-sess' ? md5(`${ha1}:${nonce}:${cnonce}`) : ha1;
16
- }
17
- constructor(credentials) {
18
- this.credentials = credentials;
19
- this.hasAuth = false;
20
- this.sentAuth = false;
21
- this.bearerToken = null;
22
- }
23
- digest(method, path, authHeader) {
24
- // TODO: More complete implementation of RFC 2617.
25
- // - support qop="auth-int" only
26
- // - handle Authentication-Info (not necessarily?)
27
- // - check challenge.stale (not necessarily?)
28
- // - increase nc (not necessarily?)
29
- // For reference:
30
- // http://tools.ietf.org/html/rfc2617#section-3
31
- // https://github.com/bagder/curl/blob/master/lib/http_digest.c
32
- const challenge = {};
33
- const re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi;
34
- while (true) {
35
- const match = re.exec(authHeader);
36
- if (!match) {
37
- break;
38
- }
39
- challenge[match[1]] = match[2] || match[3];
40
- }
41
- const qop = /(^|,)\s*auth\s*($|,)/.test(challenge.qop) && 'auth';
42
- const nc = qop && '00000001';
43
- const cnonce = qop && uuidv4().replace(/-/g, '');
44
- const ha1 = DigestAuth.ha1Compute(challenge.algorithm, this.credentials.username, challenge.realm, this.credentials.password, challenge.nonce, cnonce);
45
- const ha2 = md5(`${method}:${path}`); // lgtm [js/insufficient-password-hash]
46
- const digestResponse = qop
47
- ? md5(`${ha1}:${challenge.nonce}:${nc}:${cnonce}:${qop}:${ha2}`) // lgtm [js/insufficient-password-hash]
48
- : md5(`${ha1}:${challenge.nonce}:${ha2}`); // lgtm [js/insufficient-password-hash]
49
- const authValues = {
50
- username: this.credentials.username,
51
- realm: challenge.realm,
52
- nonce: challenge.nonce,
53
- uri: path,
54
- qop,
55
- response: digestResponse,
56
- nc,
57
- cnonce,
58
- algorithm: challenge.algorithm,
59
- opaque: challenge.opaque
60
- };
61
- const parts = [];
62
- Object.entries(authValues).forEach(([key, value]) => {
63
- if (value) {
64
- if (key === 'qop' || key === 'nc' || key === 'algorithm') {
65
- parts.push(`${key}=${value}`);
66
- }
67
- else {
68
- parts.push(`${key}="${value}"`);
69
- }
70
- }
71
- });
72
- const digest = `Digest ${parts.join(', ')}`;
73
- this.sentAuth = true;
74
- return digest;
75
- }
76
- }
77
- //# sourceMappingURL=digest-auth.js.map
@@ -1,2 +0,0 @@
1
- export * from './coverartarchive-api.js';
2
- export * from './musicbrainz-api.js';
@@ -1,3 +0,0 @@
1
- export * from './coverartarchive-api.js';
2
- export * from './musicbrainz-api.js';
3
- //# sourceMappingURL=entry-default.js.map
@@ -1,2 +0,0 @@
1
- export * from './coverartarchive-api.js';
2
- export * from './musicbrainz-api-node.js';
package/lib/entry-node.js DELETED
@@ -1,3 +0,0 @@
1
- export * from './coverartarchive-api.js';
2
- export * from './musicbrainz-api-node.js';
3
- //# sourceMappingURL=entry-node.js.map
@@ -1,11 +0,0 @@
1
- import { type Cookie } from "tough-cookie";
2
- import { HttpClient, type IHttpClientOptions } from "./http-client.js";
3
- export type HttpFormData = {
4
- [key: string]: string;
5
- };
6
- export declare class HttpClientNode extends HttpClient {
7
- private cookieJar;
8
- constructor(options: IHttpClientOptions);
9
- protected registerCookies(response: Response): Promise<Cookie | undefined>;
10
- getCookies(): Promise<string | null>;
11
- }
@@ -1,19 +0,0 @@
1
- import { CookieJar } from "tough-cookie";
2
- import { HttpClient } from "./http-client.js";
3
- export class HttpClientNode extends HttpClient {
4
- constructor(options) {
5
- super(options);
6
- this.cookieJar = new CookieJar();
7
- }
8
- registerCookies(response) {
9
- const cookie = response.headers.get('set-cookie');
10
- if (cookie) {
11
- return this.cookieJar.setCookie(cookie, response.url);
12
- }
13
- return Promise.resolve(undefined);
14
- }
15
- getCookies() {
16
- return this.cookieJar.getCookieString(this.options.baseUrl); // Get cookies for the request
17
- }
18
- }
19
- //# sourceMappingURL=http-client-node.js.map
@@ -1,28 +0,0 @@
1
- import type { Cookie } from "tough-cookie";
2
- export type HttpFormData = {
3
- [key: string]: string;
4
- };
5
- export interface IHttpClientOptions {
6
- baseUrl: string;
7
- timeout: number;
8
- userAgent: string;
9
- followRedirects?: boolean;
10
- }
11
- export interface IFetchOptions {
12
- query?: HttpFormData;
13
- retryLimit?: number;
14
- body?: string;
15
- headers?: HeadersInit;
16
- followRedirects?: boolean;
17
- }
18
- export declare class HttpClient {
19
- protected options: IHttpClientOptions;
20
- constructor(options: IHttpClientOptions);
21
- get(path: string, options?: IFetchOptions): Promise<Response>;
22
- post(path: string, options?: IFetchOptions): Promise<Response>;
23
- postForm(path: string, formData: HttpFormData, options?: IFetchOptions): Promise<Response>;
24
- postJson(path: string, json: Object, options?: IFetchOptions): Promise<Response>;
25
- private _fetch;
26
- protected registerCookies(response: Response): Promise<Cookie | undefined>;
27
- getCookies(): Promise<string | null>;
28
- }
@@ -1,50 +0,0 @@
1
- export class HttpClient {
2
- constructor(options) {
3
- this.options = options;
4
- }
5
- get(path, options) {
6
- return this._fetch('get', path, options);
7
- }
8
- post(path, options) {
9
- return this._fetch('post', path, options);
10
- }
11
- postForm(path, formData, options) {
12
- const encodedFormData = new URLSearchParams(formData).toString();
13
- return this._fetch('post', path, { ...options, body: encodedFormData, headers: { 'Content-Type': 'application/x-www-form-urlencoded' } });
14
- }
15
- // biome-ignore lint/complexity/noBannedTypes:
16
- postJson(path, json, options) {
17
- const encodedJson = JSON.stringify(json);
18
- return this._fetch('post', path, { ...options, body: encodedJson, headers: { 'Content-Type': 'application/json.' } });
19
- }
20
- async _fetch(method, path, options) {
21
- if (!options)
22
- options = {};
23
- let url = path.startsWith('/') ? `${this.options.baseUrl}${path}` : `${this.options.baseUrl}/${path}`;
24
- if (options.query) {
25
- url += `?${new URLSearchParams(options.query)}`;
26
- }
27
- const cookies = await this.getCookies();
28
- const headers = new Headers(options.headers);
29
- headers.set('User-Agent', this.options.userAgent);
30
- if (cookies !== null) {
31
- headers.set('Cookie', cookies);
32
- }
33
- const response = await fetch(url, {
34
- method,
35
- ...options,
36
- headers,
37
- body: options.body,
38
- redirect: options.followRedirects === false ? 'manual' : 'follow'
39
- });
40
- await this.registerCookies(response);
41
- return response;
42
- }
43
- registerCookies(response) {
44
- return Promise.resolve(undefined);
45
- }
46
- async getCookies() {
47
- return Promise.resolve(null);
48
- }
49
- }
50
- //# sourceMappingURL=http-client.js.map
@@ -1,16 +0,0 @@
1
- export { XmlMetadata } from './xml/xml-metadata.js';
2
- export { XmlIsrc } from './xml/xml-isrc.js';
3
- export { XmlIsrcList } from './xml/xml-isrc-list.js';
4
- export { XmlRecording } from './xml/xml-recording.js';
5
- import { HttpClientNode } from "./http-client-node.js";
6
- import { MusicBrainzApi as MusicBrainzApiDefault } from "./musicbrainz-api.js";
7
- export * from './musicbrainz.types.js';
8
- export * from './http-client.js';
9
- export declare class MusicBrainzApi extends MusicBrainzApiDefault {
10
- protected initHttpClient(): HttpClientNode;
11
- login(): Promise<boolean>;
12
- /**
13
- * Logout
14
- */
15
- logout(): Promise<boolean>;
16
- }
@@ -1,71 +0,0 @@
1
- import { StatusCodes as HttpStatus } from 'http-status-codes';
2
- import Debug from 'debug';
3
- export { XmlMetadata } from './xml/xml-metadata.js';
4
- export { XmlIsrc } from './xml/xml-isrc.js';
5
- export { XmlIsrcList } from './xml/xml-isrc-list.js';
6
- export { XmlRecording } from './xml/xml-recording.js';
7
- import { HttpClientNode } from "./http-client-node.js";
8
- import { MusicBrainzApi as MusicBrainzApiDefault } from "./musicbrainz-api.js";
9
- export * from './musicbrainz.types.js';
10
- export * from './http-client.js';
11
- /*
12
- * https://musicbrainz.org/doc/Development/XML_Web_Service/Version_2#Subqueries
13
- */
14
- const debug = Debug('musicbrainz-api-node');
15
- export class MusicBrainzApi extends MusicBrainzApiDefault {
16
- initHttpClient() {
17
- return new HttpClientNode({
18
- baseUrl: this.config.baseUrl,
19
- timeout: 20 * 1000,
20
- userAgent: `${this.config.appName}/${this.config.appVersion} ( ${this.config.appContactInfo} )`
21
- });
22
- }
23
- async login() {
24
- if (!this.config.botAccount?.username)
25
- throw new Error('bot username should be set');
26
- if (!this.config.botAccount?.password)
27
- throw new Error('bot password should be set');
28
- if (this.session?.loggedIn) {
29
- const cookies = await this.httpClient.getCookies();
30
- return cookies.indexOf('musicbrainz_server_session') !== -1;
31
- }
32
- this.session = await this.getSession();
33
- const redirectUri = '/success';
34
- const formData = {
35
- username: this.config.botAccount.username,
36
- password: this.config.botAccount.password,
37
- csrf_session_key: this.session.csrf.sessionKey,
38
- csrf_token: this.session.csrf.token,
39
- remember_me: '1'
40
- };
41
- const response = await this.httpClient.postForm('login', formData, {
42
- query: {
43
- returnto: redirectUri
44
- },
45
- followRedirects: false
46
- });
47
- const success = response.status === HttpStatus.MOVED_TEMPORARILY && response.headers.get('location') === redirectUri;
48
- if (success) {
49
- this.session.loggedIn = true;
50
- }
51
- return success;
52
- }
53
- /**
54
- * Logout
55
- */
56
- async logout() {
57
- const redirectUri = '/success';
58
- const response = await this.httpClient.post('logout', {
59
- followRedirects: false,
60
- query: {
61
- returnto: redirectUri
62
- }
63
- });
64
- const success = response.status === HttpStatus.MOVED_TEMPORARILY && response.headers.get('location') === redirectUri;
65
- if (success && this.session) {
66
- this.session.loggedIn = true;
67
- }
68
- return success;
69
- }
70
- }
71
- //# sourceMappingURL=musicbrainz-api-node.js.map