gerdur-core 2.7.0 → 2.8.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/CHANGELOG.md +23 -0
- package/README.md +18 -1
- package/dist/api/request.d.ts +8 -17
- package/dist/api/request.js +32 -84
- package/dist/converter/parse.d.ts +1 -1
- package/dist/lib/session.d.ts +40 -0
- package/dist/lib/session.js +121 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.8.0 - 2026-08-31
|
|
4
|
+
|
|
5
|
+
Phase 3.2 (cont.) — a `Session` is now usable per-account. Additive; free
|
|
6
|
+
functions unchanged.
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **`Session` query methods**: `getUser`, `getTrackInfo`, `getLyrics`,
|
|
11
|
+
`getAlbumInfo`, `getAlbumTracks`, `getPlaylistInfo`, `getPlaylistTracks`,
|
|
12
|
+
`getArtistInfo`, `getDiscography`, `getProfile`, `searchMusic` — plus the raw
|
|
13
|
+
channels `gw` / `gwLight` / `gwGet`. So `createSession(arl)` gives you an
|
|
14
|
+
isolated client you can actually query, not just inspect.
|
|
15
|
+
- Each `Session` has **its own response cache** (`session.cache`) — gateway
|
|
16
|
+
responses carry account-specific `TRACK_TOKEN`s, so sharing one cache across
|
|
17
|
+
accounts was wrong.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- `request` / `requestLight` / `requestGet` are now thin wrappers over
|
|
22
|
+
`defaultSession()`. **`initDeezerApi(newArl)` now clears the default session's
|
|
23
|
+
cache** — previously a new account could be served the old account's cached
|
|
24
|
+
track tokens.
|
|
25
|
+
|
|
3
26
|
## 2.7.0 - 2026-08-31
|
|
4
27
|
|
|
5
28
|
Phase 3.2 — session lifecycle. The scattered module-level state
|
package/README.md
CHANGED
|
@@ -114,13 +114,30 @@ module-level globals; bundling it means multiple accounts can coexist.
|
|
|
114
114
|
media-API 403.
|
|
115
115
|
- **`defaultSession()`** — the `Session` the free functions use.
|
|
116
116
|
|
|
117
|
+
Each `Session` has **its own response cache** (per-account, since gateway
|
|
118
|
+
responses carry account-specific `TRACK_TOKEN`s) and its own query methods:
|
|
119
|
+
|
|
120
|
+
| Method | |
|
|
121
|
+
| :--- | :--- |
|
|
122
|
+
| `getUser()` | this account's profile |
|
|
123
|
+
| `getTrackInfo(id)` | `song.getData` — the `TRACK_TOKEN` is this session's |
|
|
124
|
+
| `getLyrics(id)` | plain + synced lyrics |
|
|
125
|
+
| `getAlbumInfo(id)` / `getAlbumTracks(id)` | album metadata / full track list |
|
|
126
|
+
| `getPlaylistInfo(id)` / `getPlaylistTracks(id)` | playlist metadata / tracks (with `TRACK_POSITION`) |
|
|
127
|
+
| `getArtistInfo(id)` / `getDiscography(id, nb?)` | artist metadata / discography |
|
|
128
|
+
| `getProfile(userId)` | a public profile |
|
|
129
|
+
| `searchMusic(query, types?, nb?)` | search (`deezer.pageSearch`) |
|
|
130
|
+
| `gw(body, method)` / `gwLight(body, method)` / `gwGet(method, params?)` | the raw coalesced request channels |
|
|
131
|
+
| `init(arl?)` / `refreshApiToken()` / `loadUserData(force?)` / `invalidateUserData()` | lifecycle |
|
|
132
|
+
|
|
117
133
|
```js
|
|
118
134
|
await initDeezerApi(arl); // default session, as before
|
|
119
135
|
const track = await getTrackInfo('3135556');
|
|
120
136
|
|
|
121
|
-
const s = await createSession(otherArl); // a second account, isolated
|
|
137
|
+
const s = await createSession(otherArl); // a second account, fully isolated
|
|
122
138
|
await s.loadUserData();
|
|
123
139
|
console.log(s.country, s.canStreamLossless);
|
|
140
|
+
const mine = await s.getTrackInfo('3135556'); // runs against `otherArl`
|
|
124
141
|
```
|
|
125
142
|
|
|
126
143
|
### `.initDeezerApi(arl_cookie);`
|
package/dist/api/request.d.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @
|
|
4
|
-
*
|
|
2
|
+
* The gateway request helpers are now thin wrappers over the **default**
|
|
3
|
+
* {@link Session} — its per-session cache + single-flight coalescing does the
|
|
4
|
+
* de-duplication that used to live here. `createSession(arl)` gives you an
|
|
5
|
+
* isolated one whose `session.gw(...)` / `session.getTrackInfo(...)` don't share
|
|
6
|
+
* this cache.
|
|
5
7
|
*/
|
|
8
|
+
/** POST `gateway.php` (main gw channel). */
|
|
6
9
|
export declare const request: (body: object, method: string) => Promise<any>;
|
|
7
|
-
/**
|
|
8
|
-
* Make POST requests to deezer api
|
|
9
|
-
* @param {Object} body post body
|
|
10
|
-
* @param {String} method request method
|
|
11
|
-
*/
|
|
10
|
+
/** POST `gw-light.php` (search / suggest / lighter methods). */
|
|
12
11
|
export declare const requestLight: (body: object, method: string) => Promise<any>;
|
|
13
|
-
/**
|
|
14
|
-
* Make GET requests to deezer public api
|
|
15
|
-
* @param {String} method request method
|
|
16
|
-
* @param {Object} params request parameters
|
|
17
|
-
*/
|
|
12
|
+
/** GET `gateway.php` (app_page_get, user_getInfo, …). */
|
|
18
13
|
export declare const requestGet: (method: string, params?: Record<string, any>, key?: string) => Promise<any>;
|
|
19
|
-
/**
|
|
20
|
-
* Make GET requests to deezer public api
|
|
21
|
-
* @param {String} slug endpoint
|
|
22
|
-
*/
|
|
23
14
|
export declare const requestPublicApi: (slug: string) => Promise<any>;
|
package/dist/api/request.js
CHANGED
|
@@ -4,106 +4,54 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.requestPublicApi = exports.requestGet = exports.requestLight = exports.request = void 0;
|
|
7
|
-
const request_1 = __importDefault(require("../lib/request"));
|
|
8
7
|
const errors_1 = require("../lib/errors");
|
|
8
|
+
const request_1 = __importDefault(require("../lib/request"));
|
|
9
|
+
const session_1 = require("../lib/session");
|
|
9
10
|
const cache_1 = __importDefault(require("./cache"));
|
|
10
11
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
* The gateway request helpers are now thin wrappers over the **default**
|
|
13
|
+
* {@link Session} — its per-session cache + single-flight coalescing does the
|
|
14
|
+
* de-duplication that used to live here. `createSession(arl)` gives you an
|
|
15
|
+
* isolated one whose `session.gw(...)` / `session.getTrackInfo(...)` don't share
|
|
16
|
+
* this cache.
|
|
17
|
+
*/
|
|
18
|
+
/** POST `gateway.php` (main gw channel). */
|
|
19
|
+
const request = (body, method) => (0, session_1.defaultSession)().gw(body, method);
|
|
20
|
+
exports.request = request;
|
|
21
|
+
/** POST `gw-light.php` (search / suggest / lighter methods). */
|
|
22
|
+
const requestLight = (body, method) => (0, session_1.defaultSession)().gwLight(body, method);
|
|
23
|
+
exports.requestLight = requestLight;
|
|
24
|
+
/** GET `gateway.php` (app_page_get, user_getInfo, …). */
|
|
25
|
+
const requestGet = (method, params = {}, key = 'get_request') => (0, session_1.defaultSession)().gwGet(method, params, key);
|
|
26
|
+
exports.requestGet = requestGet;
|
|
27
|
+
/**
|
|
28
|
+
* GET the public REST API (`api.deezer.com`). Account-independent, so it keeps
|
|
29
|
+
* its own process-wide cache rather than a per-session one.
|
|
20
30
|
*/
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const cached = cache_1.default.get(
|
|
31
|
+
const inFlightPublic = new Map();
|
|
32
|
+
const requestPublicApi = (slug) => {
|
|
33
|
+
const cached = cache_1.default.get(slug);
|
|
24
34
|
if (cached) {
|
|
25
35
|
return Promise.resolve(cached);
|
|
26
36
|
}
|
|
27
|
-
const pending =
|
|
37
|
+
const pending = inFlightPublic.get(slug);
|
|
28
38
|
if (pending) {
|
|
29
39
|
return pending;
|
|
30
40
|
}
|
|
31
41
|
const promise = (async () => {
|
|
32
42
|
try {
|
|
33
|
-
|
|
43
|
+
const { data } = await request_1.default.get('https://api.deezer.com' + slug);
|
|
44
|
+
if (data.error) {
|
|
45
|
+
throw new errors_1.DeezerError(data.error);
|
|
46
|
+
}
|
|
47
|
+
cache_1.default.set(slug, data);
|
|
48
|
+
return data;
|
|
34
49
|
}
|
|
35
50
|
finally {
|
|
36
|
-
|
|
51
|
+
inFlightPublic.delete(slug);
|
|
37
52
|
}
|
|
38
53
|
})();
|
|
39
|
-
|
|
54
|
+
inFlightPublic.set(slug, promise);
|
|
40
55
|
return promise;
|
|
41
56
|
};
|
|
42
|
-
/**
|
|
43
|
-
* Make POST requests to deezer api
|
|
44
|
-
* @param {Object} body post body
|
|
45
|
-
* @param {String} method request method
|
|
46
|
-
*/
|
|
47
|
-
const request = async (body, method) => {
|
|
48
|
-
const cacheKey = method + ':' + Object.entries(body).join(':');
|
|
49
|
-
return coalesce(cacheKey, async () => {
|
|
50
|
-
const { data: { error, results }, } = await request_1.default.post('/gateway.php', body, { params: { method } });
|
|
51
|
-
if (results && Object.keys(results).length > 0) {
|
|
52
|
-
cache_1.default.set(cacheKey, results);
|
|
53
|
-
return results;
|
|
54
|
-
}
|
|
55
|
-
throw new errors_1.DeezerError(error);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
exports.request = request;
|
|
59
|
-
/**
|
|
60
|
-
* Make POST requests to deezer api
|
|
61
|
-
* @param {Object} body post body
|
|
62
|
-
* @param {String} method request method
|
|
63
|
-
*/
|
|
64
|
-
const requestLight = async (body, method) => {
|
|
65
|
-
const cacheKey = method + ':' + Object.entries(body).join(':');
|
|
66
|
-
return coalesce(cacheKey, async () => {
|
|
67
|
-
const { data: { error, results }, } = await request_1.default.post('https://www.deezer.com/ajax/gw-light.php', body, {
|
|
68
|
-
params: { method, api_version: '1.0' },
|
|
69
|
-
});
|
|
70
|
-
if (results && Object.keys(results).length > 0) {
|
|
71
|
-
cache_1.default.set(cacheKey, results);
|
|
72
|
-
return results;
|
|
73
|
-
}
|
|
74
|
-
throw new errors_1.DeezerError(error);
|
|
75
|
-
});
|
|
76
|
-
};
|
|
77
|
-
exports.requestLight = requestLight;
|
|
78
|
-
/**
|
|
79
|
-
* Make GET requests to deezer public api
|
|
80
|
-
* @param {String} method request method
|
|
81
|
-
* @param {Object} params request parameters
|
|
82
|
-
*/
|
|
83
|
-
const requestGet = async (method, params = {}, key = 'get_request') => {
|
|
84
|
-
const cacheKey = method + key;
|
|
85
|
-
return coalesce(cacheKey, async () => {
|
|
86
|
-
const { data: { error, results }, } = await request_1.default.get('/gateway.php', { params: { method, ...params } });
|
|
87
|
-
if (results && Object.keys(results).length > 0) {
|
|
88
|
-
cache_1.default.set(cacheKey, results);
|
|
89
|
-
return results;
|
|
90
|
-
}
|
|
91
|
-
throw new errors_1.DeezerError(error);
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
exports.requestGet = requestGet;
|
|
95
|
-
/**
|
|
96
|
-
* Make GET requests to deezer public api
|
|
97
|
-
* @param {String} slug endpoint
|
|
98
|
-
*/
|
|
99
|
-
const requestPublicApi = async (slug) => {
|
|
100
|
-
return coalesce(slug, async () => {
|
|
101
|
-
const { data } = await request_1.default.get('https://api.deezer.com' + slug);
|
|
102
|
-
if (data.error) {
|
|
103
|
-
throw new errors_1.DeezerError(data.error);
|
|
104
|
-
}
|
|
105
|
-
cache_1.default.set(slug, data);
|
|
106
|
-
return data;
|
|
107
|
-
});
|
|
108
|
-
};
|
|
109
57
|
exports.requestPublicApi = requestPublicApi;
|
|
@@ -12,7 +12,7 @@ export declare const getUrlParts: (url: string, setToken?: boolean) => Promise<u
|
|
|
12
12
|
export declare const parseInfo: (url: string) => Promise<{
|
|
13
13
|
info: urlPartsType;
|
|
14
14
|
linktype: linkType;
|
|
15
|
-
linkinfo:
|
|
15
|
+
linkinfo: artistInfoType | albumType | playlistInfo | Record<string, any>;
|
|
16
16
|
tracks: trackType[];
|
|
17
17
|
}>;
|
|
18
18
|
export {};
|
package/dist/lib/session.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import FastLRU from './fast-lru';
|
|
1
2
|
import { HttpClient } from './http';
|
|
2
3
|
import type { HttpQuery, HttpResponse } from './http';
|
|
4
|
+
import type { albumTracksType, albumType, artistInfoType, discographyType, lyricsType, playlistInfo, playlistTracksType, profileType, searchType, trackType, userType } from '../types';
|
|
5
|
+
type SearchEntity = 'ALBUM' | 'ARTIST' | 'TRACK' | 'PLAYLIST' | 'RADIO' | 'SHOW' | 'USER' | 'LIVESTREAM' | 'CHANNEL';
|
|
3
6
|
/**
|
|
4
7
|
* The bundled default `arl`. It is shared, rate-limited and expiring — good for
|
|
5
8
|
* unauthenticated endpoints, useless for downloads. `initDeezerApi` /
|
|
@@ -56,6 +59,13 @@ export declare class Session {
|
|
|
56
59
|
arl: string;
|
|
57
60
|
/** the underlying HTTP client — its `defaults.params` carry `sid` / `api_token` */
|
|
58
61
|
readonly http: HttpClient;
|
|
62
|
+
/**
|
|
63
|
+
* This session's response cache (1000 entries / 60 min). Per-session because
|
|
64
|
+
* gateway responses carry account-specific data (e.g. `TRACK_TOKEN`). Cleared
|
|
65
|
+
* when the account changes via `init(arl)`.
|
|
66
|
+
*/
|
|
67
|
+
readonly cache: FastLRU;
|
|
68
|
+
private readonly inFlight;
|
|
59
69
|
private userData;
|
|
60
70
|
private userDataAt;
|
|
61
71
|
constructor(arl?: string);
|
|
@@ -92,6 +102,36 @@ export declare class Session {
|
|
|
92
102
|
* backoff, and a wall-clock deadline. Throws `DeezerError` on exhaustion.
|
|
93
103
|
*/
|
|
94
104
|
request<T>(method: 'GET' | 'POST', url: string, body?: unknown, config?: SessionRequestConfig): Promise<HttpResponse<T>>;
|
|
105
|
+
/** Single-flight + LRU around a fetcher, keyed per session. */
|
|
106
|
+
private coalesce;
|
|
107
|
+
/** POST `gateway.php` — the main gw method channel. Coalesced + cached. */
|
|
108
|
+
gw<T = any>(body: Record<string, unknown>, method: string): Promise<T>;
|
|
109
|
+
/** POST `gw-light.php` — the lighter method channel (search, suggest, …). */
|
|
110
|
+
gwLight<T = any>(body: Record<string, unknown>, method: string): Promise<T>;
|
|
111
|
+
/** GET `gateway.php` — used for `app_page_get` and the like. */
|
|
112
|
+
gwGet<T = any>(method: string, params?: Record<string, any>, key?: string): Promise<T>;
|
|
113
|
+
/** The logged-in user's profile. */
|
|
114
|
+
getUser(): Promise<userType>;
|
|
115
|
+
/** `song.getData` for a track — includes this session's `TRACK_TOKEN`. */
|
|
116
|
+
getTrackInfo(sngId: string): Promise<trackType>;
|
|
117
|
+
/** `song.getLyrics` — plain + time-synced lyrics. */
|
|
118
|
+
getLyrics(sngId: string): Promise<lyricsType>;
|
|
119
|
+
/** `album.getData`. */
|
|
120
|
+
getAlbumInfo(albId: string): Promise<albumType>;
|
|
121
|
+
/** All of an album's tracks (`song.getListByAlbum`). */
|
|
122
|
+
getAlbumTracks(albId: string): Promise<albumTracksType>;
|
|
123
|
+
/** `playlist.getData`. */
|
|
124
|
+
getPlaylistInfo(playlistId: string): Promise<playlistInfo>;
|
|
125
|
+
/** All of a playlist's tracks, with `TRACK_POSITION` filled in. */
|
|
126
|
+
getPlaylistTracks(playlistId: string): Promise<playlistTracksType>;
|
|
127
|
+
/** `artist.getData`. */
|
|
128
|
+
getArtistInfo(artId: string): Promise<artistInfoType>;
|
|
129
|
+
/** An artist's discography (`album.getDiscography`). */
|
|
130
|
+
getDiscography(artId: string, nb?: number): Promise<discographyType>;
|
|
131
|
+
/** A public profile (`mobile.pageUser`). */
|
|
132
|
+
getProfile(userId: string): Promise<profileType>;
|
|
133
|
+
/** Search (`deezer.pageSearch`). `types` defaults to `['TRACK']`. */
|
|
134
|
+
searchMusic(query: string, types?: SearchEntity[], nb?: number): Promise<searchType>;
|
|
95
135
|
}
|
|
96
136
|
/** The process-wide default session every free function runs against. */
|
|
97
137
|
export declare const defaultSession: () => Session;
|
package/dist/lib/session.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.setDefaultSession = exports.createSession = exports.initDeezerApi = exports.defaultSession = exports.Session = exports.RETRY_POLICY = exports.DEFAULT_ARL = void 0;
|
|
7
7
|
const delay_1 = __importDefault(require("delay"));
|
|
8
8
|
const errors_1 = require("./errors");
|
|
9
|
+
const fast_lru_1 = __importDefault(require("./fast-lru"));
|
|
9
10
|
const http_1 = require("./http");
|
|
10
11
|
/**
|
|
11
12
|
* The bundled default `arl`. It is shared, rate-limited and expiring — good for
|
|
@@ -51,6 +52,13 @@ const USER_DATA_TTL_MS = 25 * 60 * 1000;
|
|
|
51
52
|
*/
|
|
52
53
|
class Session {
|
|
53
54
|
constructor(arl) {
|
|
55
|
+
/**
|
|
56
|
+
* This session's response cache (1000 entries / 60 min). Per-session because
|
|
57
|
+
* gateway responses carry account-specific data (e.g. `TRACK_TOKEN`). Cleared
|
|
58
|
+
* when the account changes via `init(arl)`.
|
|
59
|
+
*/
|
|
60
|
+
this.cache = new fast_lru_1.default({ maxSize: 1000, ttl: 60 * 60000 });
|
|
61
|
+
this.inFlight = new Map();
|
|
54
62
|
this.userData = null;
|
|
55
63
|
this.userDataAt = 0;
|
|
56
64
|
this.arl = arl !== null && arl !== void 0 ? arl : exports.DEFAULT_ARL;
|
|
@@ -115,6 +123,7 @@ class Session {
|
|
|
115
123
|
}
|
|
116
124
|
this.arl = arl;
|
|
117
125
|
this.userData = null;
|
|
126
|
+
this.cache.clear();
|
|
118
127
|
}
|
|
119
128
|
const { data } = await this.http.get('https://www.deezer.com/ajax/gw-light.php', {
|
|
120
129
|
params: { method: 'deezer.ping', api_version: '1.0', api_token: '' },
|
|
@@ -207,6 +216,118 @@ class Session {
|
|
|
207
216
|
throw new errors_1.DeezerError(error);
|
|
208
217
|
}
|
|
209
218
|
}
|
|
219
|
+
// ─── Cached request primitives ──────────────────────────────────────────────
|
|
220
|
+
/** Single-flight + LRU around a fetcher, keyed per session. */
|
|
221
|
+
coalesce(key, fetcher) {
|
|
222
|
+
const cached = this.cache.get(key);
|
|
223
|
+
if (cached) {
|
|
224
|
+
return Promise.resolve(cached);
|
|
225
|
+
}
|
|
226
|
+
const pending = this.inFlight.get(key);
|
|
227
|
+
if (pending) {
|
|
228
|
+
return pending;
|
|
229
|
+
}
|
|
230
|
+
const promise = (async () => {
|
|
231
|
+
try {
|
|
232
|
+
return await fetcher();
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
this.inFlight.delete(key);
|
|
236
|
+
}
|
|
237
|
+
})();
|
|
238
|
+
this.inFlight.set(key, promise);
|
|
239
|
+
return promise;
|
|
240
|
+
}
|
|
241
|
+
/** POST `gateway.php` — the main gw method channel. Coalesced + cached. */
|
|
242
|
+
gw(body, method) {
|
|
243
|
+
const key = `gw:${method}:${Object.entries(body).join(':')}`;
|
|
244
|
+
return this.coalesce(key, async () => {
|
|
245
|
+
const { data: { error, results }, } = await this.request('POST', '/gateway.php', body, { params: { method } });
|
|
246
|
+
if (results && Object.keys(results).length > 0) {
|
|
247
|
+
this.cache.set(key, results);
|
|
248
|
+
return results;
|
|
249
|
+
}
|
|
250
|
+
throw new errors_1.DeezerError(error);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/** POST `gw-light.php` — the lighter method channel (search, suggest, …). */
|
|
254
|
+
gwLight(body, method) {
|
|
255
|
+
const key = `gwl:${method}:${Object.entries(body).join(':')}`;
|
|
256
|
+
return this.coalesce(key, async () => {
|
|
257
|
+
const { data: { error, results }, } = await this.request('POST', 'https://www.deezer.com/ajax/gw-light.php', body, {
|
|
258
|
+
params: { method, api_version: '1.0' },
|
|
259
|
+
});
|
|
260
|
+
if (results && Object.keys(results).length > 0) {
|
|
261
|
+
this.cache.set(key, results);
|
|
262
|
+
return results;
|
|
263
|
+
}
|
|
264
|
+
throw new errors_1.DeezerError(error);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
/** GET `gateway.php` — used for `app_page_get` and the like. */
|
|
268
|
+
gwGet(method, params = {}, key = 'get_request') {
|
|
269
|
+
const cacheKey = `gwget:${method}:${key}`;
|
|
270
|
+
return this.coalesce(cacheKey, async () => {
|
|
271
|
+
const { data: { error, results }, } = await this.request('GET', '/gateway.php', undefined, {
|
|
272
|
+
params: { method, ...params },
|
|
273
|
+
});
|
|
274
|
+
if (results && Object.keys(results).length > 0) {
|
|
275
|
+
this.cache.set(cacheKey, results);
|
|
276
|
+
return results;
|
|
277
|
+
}
|
|
278
|
+
throw new errors_1.DeezerError(error);
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
// ─── Query methods (this account's view) ────────────────────────────────────
|
|
282
|
+
/** The logged-in user's profile. */
|
|
283
|
+
getUser() {
|
|
284
|
+
return this.gwGet('user_getInfo');
|
|
285
|
+
}
|
|
286
|
+
/** `song.getData` for a track — includes this session's `TRACK_TOKEN`. */
|
|
287
|
+
getTrackInfo(sngId) {
|
|
288
|
+
return this.gw({ sng_id: sngId }, 'song.getData');
|
|
289
|
+
}
|
|
290
|
+
/** `song.getLyrics` — plain + time-synced lyrics. */
|
|
291
|
+
getLyrics(sngId) {
|
|
292
|
+
return this.gw({ sng_id: sngId }, 'song.getLyrics');
|
|
293
|
+
}
|
|
294
|
+
/** `album.getData`. */
|
|
295
|
+
getAlbumInfo(albId) {
|
|
296
|
+
return this.gw({ alb_id: albId }, 'album.getData');
|
|
297
|
+
}
|
|
298
|
+
/** All of an album's tracks (`song.getListByAlbum`). */
|
|
299
|
+
getAlbumTracks(albId) {
|
|
300
|
+
return this.gw({ alb_id: albId, lang: 'us', nb: -1 }, 'song.getListByAlbum');
|
|
301
|
+
}
|
|
302
|
+
/** `playlist.getData`. */
|
|
303
|
+
getPlaylistInfo(playlistId) {
|
|
304
|
+
return this.gw({ playlist_id: playlistId, lang: 'en' }, 'playlist.getData');
|
|
305
|
+
}
|
|
306
|
+
/** All of a playlist's tracks, with `TRACK_POSITION` filled in. */
|
|
307
|
+
async getPlaylistTracks(playlistId) {
|
|
308
|
+
const res = await this.gw({ playlist_id: playlistId, lang: 'en', nb: -1, start: 0, tab: 0, tags: true, header: true }, 'playlist.getSongs');
|
|
309
|
+
res.data = res.data.map((t, i) => {
|
|
310
|
+
t.TRACK_POSITION = i + 1;
|
|
311
|
+
return t;
|
|
312
|
+
});
|
|
313
|
+
return res;
|
|
314
|
+
}
|
|
315
|
+
/** `artist.getData`. */
|
|
316
|
+
getArtistInfo(artId) {
|
|
317
|
+
return this.gw({ art_id: artId, filter_role_id: [0], lang: 'en', tab: 0, nb: -1, start: 0 }, 'artist.getData');
|
|
318
|
+
}
|
|
319
|
+
/** An artist's discography (`album.getDiscography`). */
|
|
320
|
+
getDiscography(artId, nb = 500) {
|
|
321
|
+
return this.gw({ art_id: artId, filter_role_id: [0], lang: 'en', nb, nb_songs: -1, start: 0 }, 'album.getDiscography');
|
|
322
|
+
}
|
|
323
|
+
/** A public profile (`mobile.pageUser`). */
|
|
324
|
+
getProfile(userId) {
|
|
325
|
+
return this.gw({ user_id: userId, tab: 'loved', nb: -1 }, 'mobile.pageUser');
|
|
326
|
+
}
|
|
327
|
+
/** Search (`deezer.pageSearch`). `types` defaults to `['TRACK']`. */
|
|
328
|
+
searchMusic(query, types = ['TRACK'], nb = 15) {
|
|
329
|
+
return this.gwLight({ query, start: 0, nb, suggest: true, artist_suggest: true, top_tracks: true, types }, 'deezer.pageSearch');
|
|
330
|
+
}
|
|
210
331
|
}
|
|
211
332
|
exports.Session = Session;
|
|
212
333
|
let _default = new Session();
|