gerdur-core 0.0.0-probe → 1.0.1
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 +10 -0
- package/LICENSE +0 -0
- package/README.md +186 -1
- package/dist/api/api.d.ts +78 -0
- package/dist/api/api.js +182 -0
- package/dist/api/cache.d.ts +3 -0
- package/dist/api/cache.js +12 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +18 -0
- package/dist/api/request.d.ts +23 -0
- package/dist/api/request.js +88 -0
- package/dist/converter/deezer.d.ts +3 -0
- package/dist/converter/deezer.js +45 -0
- package/dist/converter/index.d.ts +5 -0
- package/dist/converter/index.js +34 -0
- package/dist/converter/parse.d.ts +18 -0
- package/dist/converter/parse.js +176 -0
- package/dist/converter/spotify.d.ts +40 -0
- package/dist/converter/spotify.js +154 -0
- package/dist/converter/tidal.d.ts +146 -0
- package/dist/converter/tidal.js +199 -0
- package/dist/converter/youtube.d.ts +6 -0
- package/dist/converter/youtube.js +102 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +24 -0
- package/dist/lib/decrypt.d.ts +9 -0
- package/dist/lib/decrypt.js +63 -0
- package/dist/lib/fast-lru.d.ts +63 -0
- package/dist/lib/fast-lru.js +121 -0
- package/dist/lib/get-url.d.ts +16 -0
- package/dist/lib/get-url.js +154 -0
- package/dist/lib/http.d.ts +66 -0
- package/dist/lib/http.js +235 -0
- package/dist/lib/metaflac-js.d.ts +124 -0
- package/dist/lib/metaflac-js.js +343 -0
- package/dist/lib/request.d.ts +18 -0
- package/dist/lib/request.js +86 -0
- package/dist/metadata-writer/abumCover.d.ts +10 -0
- package/dist/metadata-writer/abumCover.js +37 -0
- package/dist/metadata-writer/flacmetata.d.ts +3 -0
- package/dist/metadata-writer/flacmetata.js +80 -0
- package/dist/metadata-writer/getTrackLyrics.d.ts +2 -0
- package/dist/metadata-writer/getTrackLyrics.js +26 -0
- package/dist/metadata-writer/id3.d.ts +3 -0
- package/dist/metadata-writer/id3.js +119 -0
- package/dist/metadata-writer/index.d.ts +9 -0
- package/dist/metadata-writer/index.js +44 -0
- package/dist/metadata-writer/musixmatchLyrics.d.ts +1 -0
- package/dist/metadata-writer/musixmatchLyrics.js +39 -0
- package/dist/metadata-writer/useragents.d.ts +1 -0
- package/dist/metadata-writer/useragents.js +86 -0
- package/dist/types/album.d.ts +123 -0
- package/dist/types/album.js +2 -0
- package/dist/types/artist.d.ts +36 -0
- package/dist/types/artist.js +2 -0
- package/dist/types/channel.d.ts +33 -0
- package/dist/types/channel.js +2 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.js +26 -0
- package/dist/types/playlist-channel.d.ts +81 -0
- package/dist/types/playlist-channel.js +2 -0
- package/dist/types/playlist.d.ts +49 -0
- package/dist/types/playlist.js +2 -0
- package/dist/types/profile.d.ts +29 -0
- package/dist/types/profile.js +2 -0
- package/dist/types/radio.d.ts +7 -0
- package/dist/types/radio.js +2 -0
- package/dist/types/search.d.ts +79 -0
- package/dist/types/search.js +2 -0
- package/dist/types/show.d.ts +61 -0
- package/dist/types/show.js +2 -0
- package/dist/types/tracks.d.ts +144 -0
- package/dist/types/tracks.js +2 -0
- package/dist/types/user.d.ts +16 -0
- package/dist/types/user.js +2 -0
- package/package.json +67 -5
- package/types/index.d.ts +1 -0
- package/types/index.js +3 -0
- package/types/package.json +4 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.1 - 2026-08-30
|
|
4
|
+
|
|
5
|
+
Initial public release.
|
|
6
|
+
|
|
7
|
+
- Deezer gateway client with transparent token refresh and rate-limit backoff, on a dependency-light internal HTTP transport.
|
|
8
|
+
- Spotify / Tidal / YouTube URL resolution to Deezer tracks via ISRC and UPC matching.
|
|
9
|
+
- Blowfish stripe decryption (`decryptDownload`), download-URL resolution with licence and geo checks (`getTrackDownloadUrl`), ID3 / FLAC metadata writing (`addTrackTags`).
|
|
10
|
+
- Shared TypeScript types, also published as the `gerdur-core/types` subpath.
|
package/LICENSE
ADDED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,3 +1,188 @@
|
|
|
1
1
|
# gerdur-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The engine behind [`gerdur`](https://github.com/soulwax/gerdur): the streaming-service API clients, URL resolution, track decryption, and metadata tagging. Also used across the darkfloor / hexmusic services.
|
|
4
|
+
|
|
5
|
+
Source: <https://github.com/soulwax/gerdur-core> · npm: <https://www.npmjs.com/package/gerdur-core>
|
|
6
|
+
|
|
7
|
+
## Why *gerdur*?
|
|
8
|
+
|
|
9
|
+
**Gerðr** is the jötunn Freyr sends his servant Skírnir riding through a wall of fire to fetch; her name, *garðr*, means "the enclosure, the walled garden" (cf. English *garden*). `gerdur-core` does the crossing — resolving identifiers, getting past the wall, decrypting the stream, and handing back a finished, tagged track. The [`gerdur`](https://github.com/soulwax/gerdur) CLI is a thin shell around it.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i gerdur-core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
yarn add gerdur-core
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pnpm add gerdur-core
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Type declarations are also published under the `gerdur-core/types` subpath for consumers that want to import the shared library types directly.
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
Here's a simple example to download tracks.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import fs from 'fs';
|
|
33
|
+
import {get} from 'https';
|
|
34
|
+
import * as api from 'gerdur-core';
|
|
35
|
+
|
|
36
|
+
const downloadBuffer = (url: string) =>
|
|
37
|
+
new Promise<Buffer>((resolve, reject) => {
|
|
38
|
+
get(url, (response) => {
|
|
39
|
+
const chunks: Buffer[] = [];
|
|
40
|
+
response.on('data', (chunk) => chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
|
|
41
|
+
response.on('end', () => resolve(Buffer.concat(chunks)));
|
|
42
|
+
response.on('error', reject);
|
|
43
|
+
}).on('error', reject);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Init api with arl from cookie
|
|
47
|
+
await api.initDeezerApi(arl_cookie);
|
|
48
|
+
|
|
49
|
+
// Verify user
|
|
50
|
+
try {
|
|
51
|
+
const user = await api.getUser();
|
|
52
|
+
// Successfully logged in
|
|
53
|
+
console.log('Logged in as ' + user.BLOG_NAME);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// Invalid arl cookie set
|
|
56
|
+
console.error(err.message);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// GET Track Object
|
|
60
|
+
const track = await api.getTrackInfo(song_id);
|
|
61
|
+
|
|
62
|
+
// Parse download URL for 128kbps
|
|
63
|
+
const trackData = await api.getTrackDownloadUrl(track, 1);
|
|
64
|
+
|
|
65
|
+
// Download track
|
|
66
|
+
const data = await downloadBuffer(trackData.trackUrl);
|
|
67
|
+
|
|
68
|
+
// Decrypt track if needed
|
|
69
|
+
const outFile = trackData.isEncrypted ? api.decryptDownload(data, track.SNG_ID) : data;
|
|
70
|
+
|
|
71
|
+
// Add id3 metadata
|
|
72
|
+
const trackWithMetadata = await api.addTrackTags(outFile, track, 500);
|
|
73
|
+
|
|
74
|
+
// Save file to disk
|
|
75
|
+
fs.writeFileSync(track.SNG_TITLE + '.mp3', trackWithMetadata);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### [Read FAQ](docs/faq.md)
|
|
79
|
+
|
|
80
|
+
## Methods
|
|
81
|
+
|
|
82
|
+
All method returns `Object` or throws `Error`. Make sure to catch error on your side.
|
|
83
|
+
|
|
84
|
+
### `.initDeezerApi(arl_cookie);`
|
|
85
|
+
|
|
86
|
+
> It is recommended that you first init the app with this method using your arl cookie.
|
|
87
|
+
|
|
88
|
+
| Parameters | Required | Type |
|
|
89
|
+
| ------------ | :------: | -------: |
|
|
90
|
+
| `arl_cookie` | Yes | `string` |
|
|
91
|
+
|
|
92
|
+
### `.getTrackInfo(track_id);`
|
|
93
|
+
|
|
94
|
+
| Parameters | Required | Type |
|
|
95
|
+
| ---------- | :------: | -------: |
|
|
96
|
+
| `track_id` | Yes | `string` |
|
|
97
|
+
|
|
98
|
+
### `.getLyrics(track_id);`
|
|
99
|
+
|
|
100
|
+
| Parameters | Required | Type |
|
|
101
|
+
| ---------- | :------: | -------: |
|
|
102
|
+
| `track_id` | Yes | `string` |
|
|
103
|
+
|
|
104
|
+
### `.getAlbumInfo(album_id);`
|
|
105
|
+
|
|
106
|
+
| Parameters | Required | Type |
|
|
107
|
+
| ---------- | :------: | -------: |
|
|
108
|
+
| `album_id` | Yes | `string` |
|
|
109
|
+
|
|
110
|
+
### `.getAlbumTracks(album_id);`
|
|
111
|
+
|
|
112
|
+
| Parameters | Required | Type |
|
|
113
|
+
| ---------- | :------: | -------: |
|
|
114
|
+
| `album_id` | Yes | `string` |
|
|
115
|
+
|
|
116
|
+
### `.getPlaylistInfo(playlist_id);`
|
|
117
|
+
|
|
118
|
+
| Parameters | Required | Type |
|
|
119
|
+
| ------------- | :------: | -------: |
|
|
120
|
+
| `playlist_id` | Yes | `string` |
|
|
121
|
+
|
|
122
|
+
### `.getPlaylistTracks(playlist_id);`
|
|
123
|
+
|
|
124
|
+
| Parameters | Required | Type |
|
|
125
|
+
| ------------- | :------: | -------: |
|
|
126
|
+
| `playlist_id` | Yes | `string` |
|
|
127
|
+
|
|
128
|
+
### `.getArtistInfo(artist_id);`
|
|
129
|
+
|
|
130
|
+
| Parameters | Required | Type |
|
|
131
|
+
| ----------- | :------: | -------: |
|
|
132
|
+
| `artist_id` | Yes | `string` |
|
|
133
|
+
|
|
134
|
+
### `.getDiscography(artist_id, limit);`
|
|
135
|
+
|
|
136
|
+
| Parameters | Required | Type | Default | Description |
|
|
137
|
+
| ----------- | :------: | -------: | ------: | ----------------------: |
|
|
138
|
+
| `artist_id` | Yes | `string` | - | artist id |
|
|
139
|
+
| `limit` | No | `number` | 500 | maximum tracks to fetch |
|
|
140
|
+
|
|
141
|
+
### `.getProfile(user_id);`
|
|
142
|
+
|
|
143
|
+
| Parameters | Required | Type |
|
|
144
|
+
| ---------- | :------: | -------: |
|
|
145
|
+
| `user_id` | Yes | `string` |
|
|
146
|
+
|
|
147
|
+
### `.searchAlternative(artist_name, song_name);`
|
|
148
|
+
|
|
149
|
+
| Parameters | Required | Type |
|
|
150
|
+
| ------------- | :------: | -------: |
|
|
151
|
+
| `artist_name` | Yes | `string` |
|
|
152
|
+
| `song_name` | Yes | `string` |
|
|
153
|
+
|
|
154
|
+
### `.searchMusic(query, types, limit);`
|
|
155
|
+
|
|
156
|
+
| Parameters | Required | Type | Default | Description |
|
|
157
|
+
| ---------- | :------: | -------: | --------: | ------------------------------: |
|
|
158
|
+
| `query` | Yes | `string` | - | search query |
|
|
159
|
+
| `types` | No | `array` | ['TRACK'] | array of search types |
|
|
160
|
+
| `limit` | No | `number` | 15 | maximum item to fetch per types |
|
|
161
|
+
|
|
162
|
+
### `.getTrackDownloadUrl(track, quality);`
|
|
163
|
+
|
|
164
|
+
| Parameters | Required | Type | Description |
|
|
165
|
+
| ---------- | :------: | ----------: | ---------------------------------: |
|
|
166
|
+
| `track` | Yes | `string` | track object |
|
|
167
|
+
| `quality` | Yes | `1, 3 or 9` | 1 = 128kbps, 3 = 320kbps, 9 = flac |
|
|
168
|
+
|
|
169
|
+
### `.decryptDownload(data, song_id);`
|
|
170
|
+
|
|
171
|
+
| Parameters | Required | Type | Description |
|
|
172
|
+
| ---------- | :------: | -------: | ---------------------: |
|
|
173
|
+
| `data` | Yes | `buffer` | downloaded song buffer |
|
|
174
|
+
| `song_id` | Yes | `string` | track id |
|
|
175
|
+
|
|
176
|
+
### `.addTrackTags(data, track,coverSize)`
|
|
177
|
+
|
|
178
|
+
| Parameters | Required | Type | Description |
|
|
179
|
+
| ----------- | :------: | --------: | ---------------------: |
|
|
180
|
+
| `data` | Yes | `buffer` | downloaded song buffer |
|
|
181
|
+
| `track` | Yes | `string` | track object |
|
|
182
|
+
| `coverSize` | No | `56-1800` | cover art size |
|
|
183
|
+
|
|
184
|
+
###
|
|
185
|
+
|
|
186
|
+
> We are not responsible for any misuse of this library by any third party. Please make sure to respect the artists and the music industry when using this library.
|
|
187
|
+
|
|
188
|
+
> Made with :heart: by the Bluesix Team. If you want to contribute, please read the [contributing guidelines](.github/CONTRIBUTING.md) first.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { albumType, trackType, lyricsType, albumTracksType, showType, playlistInfo, playlistTracksType, playlistChannelType, channelSearchType, artistInfoType, discographyType, profileType, searchType, trackTypePublicApi, albumTypePublicApi, userType } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* @param {String} sng_id song id
|
|
4
|
+
*/
|
|
5
|
+
export declare const getTrackInfoPublicApi: (sng_id: string) => Promise<trackTypePublicApi>;
|
|
6
|
+
/**
|
|
7
|
+
* @param {String} alb_id album id
|
|
8
|
+
*/
|
|
9
|
+
export declare const getAlbumInfoPublicApi: (alb_id: string) => Promise<albumTypePublicApi>;
|
|
10
|
+
/**
|
|
11
|
+
* @param {String} sng_id song id
|
|
12
|
+
*/
|
|
13
|
+
export declare const getTrackInfo: (sng_id: string) => Promise<trackType>;
|
|
14
|
+
/**
|
|
15
|
+
* @param {String} sng_id song id
|
|
16
|
+
*/
|
|
17
|
+
export declare const getLyrics: (sng_id: string) => Promise<lyricsType>;
|
|
18
|
+
/**
|
|
19
|
+
* @param {String} alb_id album id
|
|
20
|
+
*/
|
|
21
|
+
export declare const getAlbumInfo: (alb_id: string) => Promise<albumType>;
|
|
22
|
+
/**
|
|
23
|
+
* @param {String} alb_id user id
|
|
24
|
+
*/
|
|
25
|
+
export declare const getAlbumTracks: (alb_id: string) => Promise<albumTracksType>;
|
|
26
|
+
/**
|
|
27
|
+
* @param {String} playlist_id playlist id
|
|
28
|
+
*/
|
|
29
|
+
export declare const getPlaylistInfo: (playlist_id: string) => Promise<playlistInfo>;
|
|
30
|
+
/**
|
|
31
|
+
* @param {String} playlist_id playlist id
|
|
32
|
+
*/
|
|
33
|
+
export declare const getPlaylistTracks: (playlist_id: string) => Promise<playlistTracksType>;
|
|
34
|
+
/**
|
|
35
|
+
* @param {String} art_id artist id
|
|
36
|
+
*/
|
|
37
|
+
export declare const getArtistInfo: (art_id: string) => Promise<artistInfoType>;
|
|
38
|
+
/**
|
|
39
|
+
* @param {String} art_id artist id
|
|
40
|
+
* @param {String} nb number of total song to fetch
|
|
41
|
+
*/
|
|
42
|
+
export declare const getDiscography: (art_id: string, nb?: number) => Promise<discographyType>;
|
|
43
|
+
/**
|
|
44
|
+
* @param {String} user_id user id
|
|
45
|
+
*/
|
|
46
|
+
export declare const getProfile: (user_id: string) => Promise<profileType>;
|
|
47
|
+
/**
|
|
48
|
+
* @param {String} artist artist name
|
|
49
|
+
* @param {String} song song name
|
|
50
|
+
* @param {String} nb number of items to fetch
|
|
51
|
+
*/
|
|
52
|
+
export declare const searchAlternative: (artist: string, song: string, nb?: number) => Promise<searchType>;
|
|
53
|
+
type searchTypesProp = 'ALBUM' | 'ARTIST' | 'TRACK' | 'PLAYLIST' | 'RADIO' | 'SHOW' | 'USER' | 'LIVESTREAM' | 'CHANNEL';
|
|
54
|
+
/**
|
|
55
|
+
* @param {String} query search query
|
|
56
|
+
* @param {Array} types search types
|
|
57
|
+
* @param {Number} nb number of items to fetch
|
|
58
|
+
*/
|
|
59
|
+
export declare const searchMusic: (query: string, types?: searchTypesProp[], nb?: number) => Promise<searchType>;
|
|
60
|
+
/**
|
|
61
|
+
* Get details about current user
|
|
62
|
+
*/
|
|
63
|
+
export declare const getUser: () => Promise<userType>;
|
|
64
|
+
/**
|
|
65
|
+
* Get list of channles
|
|
66
|
+
*/
|
|
67
|
+
export declare const getChannelList: () => Promise<channelSearchType>;
|
|
68
|
+
/**
|
|
69
|
+
* @param {String} SHOW_ID show id
|
|
70
|
+
* @param {Number} NB number of items to fetch
|
|
71
|
+
* @param {Number} START start index
|
|
72
|
+
*/
|
|
73
|
+
export declare const getShowInfo: (SHOW_ID: string, NB?: number, START?: number) => Promise<showType>;
|
|
74
|
+
/**
|
|
75
|
+
* Get details about a playlist channel
|
|
76
|
+
*/
|
|
77
|
+
export declare const getPlaylistChannel: (page: string) => Promise<playlistChannelType>;
|
|
78
|
+
export {};
|
package/dist/api/api.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getPlaylistChannel = exports.getShowInfo = exports.getChannelList = exports.getUser = exports.searchMusic = exports.searchAlternative = exports.getProfile = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getLyrics = exports.getTrackInfo = exports.getAlbumInfoPublicApi = exports.getTrackInfoPublicApi = void 0;
|
|
4
|
+
const request_1 = require("./request");
|
|
5
|
+
/**
|
|
6
|
+
* @param {String} sng_id song id
|
|
7
|
+
*/
|
|
8
|
+
const getTrackInfoPublicApi = (sng_id) => (0, request_1.requestPublicApi)('/track/' + sng_id);
|
|
9
|
+
exports.getTrackInfoPublicApi = getTrackInfoPublicApi;
|
|
10
|
+
/**
|
|
11
|
+
* @param {String} alb_id album id
|
|
12
|
+
*/
|
|
13
|
+
const getAlbumInfoPublicApi = (alb_id) => (0, request_1.requestPublicApi)('/album/' + alb_id);
|
|
14
|
+
exports.getAlbumInfoPublicApi = getAlbumInfoPublicApi;
|
|
15
|
+
/**
|
|
16
|
+
* @param {String} sng_id song id
|
|
17
|
+
*/
|
|
18
|
+
const getTrackInfo = (sng_id) => (0, request_1.request)({ sng_id }, 'song.getData');
|
|
19
|
+
exports.getTrackInfo = getTrackInfo;
|
|
20
|
+
/**
|
|
21
|
+
* @param {String} sng_id song id
|
|
22
|
+
*/
|
|
23
|
+
const getLyrics = (sng_id) => (0, request_1.request)({ sng_id }, 'song.getLyrics');
|
|
24
|
+
exports.getLyrics = getLyrics;
|
|
25
|
+
/**
|
|
26
|
+
* @param {String} alb_id album id
|
|
27
|
+
*/
|
|
28
|
+
const getAlbumInfo = (alb_id) => (0, request_1.request)({ alb_id }, 'album.getData');
|
|
29
|
+
exports.getAlbumInfo = getAlbumInfo;
|
|
30
|
+
/**
|
|
31
|
+
* @param {String} alb_id user id
|
|
32
|
+
*/
|
|
33
|
+
const getAlbumTracks = async (alb_id) => (0, request_1.request)({ alb_id, lang: 'us', nb: -1 }, 'song.getListByAlbum');
|
|
34
|
+
exports.getAlbumTracks = getAlbumTracks;
|
|
35
|
+
/**
|
|
36
|
+
* @param {String} playlist_id playlist id
|
|
37
|
+
*/
|
|
38
|
+
const getPlaylistInfo = (playlist_id) => (0, request_1.request)({ playlist_id, lang: 'en' }, 'playlist.getData');
|
|
39
|
+
exports.getPlaylistInfo = getPlaylistInfo;
|
|
40
|
+
/**
|
|
41
|
+
* @param {String} playlist_id playlist id
|
|
42
|
+
*/
|
|
43
|
+
const getPlaylistTracks = async (playlist_id) => {
|
|
44
|
+
const playlistTracks = await (0, request_1.request)({ playlist_id, lang: 'en', nb: -1, start: 0, tab: 0, tags: true, header: true }, 'playlist.getSongs');
|
|
45
|
+
playlistTracks.data = playlistTracks.data.map((track, index) => {
|
|
46
|
+
track.TRACK_POSITION = index + 1;
|
|
47
|
+
return track;
|
|
48
|
+
});
|
|
49
|
+
return playlistTracks;
|
|
50
|
+
};
|
|
51
|
+
exports.getPlaylistTracks = getPlaylistTracks;
|
|
52
|
+
/**
|
|
53
|
+
* @param {String} art_id artist id
|
|
54
|
+
*/
|
|
55
|
+
const getArtistInfo = (art_id) => (0, request_1.request)({ art_id, filter_role_id: [0], lang: 'en', tab: 0, nb: -1, start: 0 }, 'artist.getData');
|
|
56
|
+
exports.getArtistInfo = getArtistInfo;
|
|
57
|
+
/**
|
|
58
|
+
* @param {String} art_id artist id
|
|
59
|
+
* @param {String} nb number of total song to fetch
|
|
60
|
+
*/
|
|
61
|
+
const getDiscography = (art_id, nb = 500) => (0, request_1.request)({ art_id, filter_role_id: [0], lang: 'en', nb, nb_songs: -1, start: 0 }, 'album.getDiscography');
|
|
62
|
+
exports.getDiscography = getDiscography;
|
|
63
|
+
/**
|
|
64
|
+
* @param {String} user_id user id
|
|
65
|
+
*/
|
|
66
|
+
const getProfile = (user_id) => (0, request_1.request)({ user_id, tab: 'loved', nb: -1 }, 'mobile.pageUser');
|
|
67
|
+
exports.getProfile = getProfile;
|
|
68
|
+
/**
|
|
69
|
+
* @param {String} artist artist name
|
|
70
|
+
* @param {String} song song name
|
|
71
|
+
* @param {String} nb number of items to fetch
|
|
72
|
+
*/
|
|
73
|
+
const searchAlternative = (artist, song, nb = 10) => (0, request_1.request)({
|
|
74
|
+
query: `artist:'${artist}' track:'${song}'`,
|
|
75
|
+
types: ['TRACK'],
|
|
76
|
+
nb,
|
|
77
|
+
}, 'mobile_suggest');
|
|
78
|
+
exports.searchAlternative = searchAlternative;
|
|
79
|
+
/**
|
|
80
|
+
* @param {String} query search query
|
|
81
|
+
* @param {Array} types search types
|
|
82
|
+
* @param {Number} nb number of items to fetch
|
|
83
|
+
*/
|
|
84
|
+
const searchMusic = (query, types = ['TRACK'], nb = 15) => (0, request_1.requestLight)({ query, start: 0, nb, suggest: true, artist_suggest: true, top_tracks: true }, 'deezer.pageSearch');
|
|
85
|
+
exports.searchMusic = searchMusic;
|
|
86
|
+
/**
|
|
87
|
+
* Get details about current user
|
|
88
|
+
*/
|
|
89
|
+
const getUser = async () => (0, request_1.requestGet)('user_getInfo');
|
|
90
|
+
exports.getUser = getUser;
|
|
91
|
+
/**
|
|
92
|
+
* Get list of channles
|
|
93
|
+
*/
|
|
94
|
+
const getChannelList = async () => (0, request_1.request)({}, 'search_getChannels');
|
|
95
|
+
exports.getChannelList = getChannelList;
|
|
96
|
+
/**
|
|
97
|
+
* @param {String} SHOW_ID show id
|
|
98
|
+
* @param {Number} NB number of items to fetch
|
|
99
|
+
* @param {Number} START start index
|
|
100
|
+
*/
|
|
101
|
+
const getShowInfo = (SHOW_ID, NB = 1000, START = 0) => (0, request_1.request)({
|
|
102
|
+
SHOW_ID,
|
|
103
|
+
NB,
|
|
104
|
+
START,
|
|
105
|
+
}, 'mobile.pageShow');
|
|
106
|
+
exports.getShowInfo = getShowInfo;
|
|
107
|
+
/**
|
|
108
|
+
* Get details about a playlist channel
|
|
109
|
+
*/
|
|
110
|
+
const getPlaylistChannel = async (page) => {
|
|
111
|
+
const gateway_input = {
|
|
112
|
+
page,
|
|
113
|
+
version: '2.3',
|
|
114
|
+
support: {
|
|
115
|
+
'long-card-horizontal-grid': ['album', 'playlist', 'radio', 'show'],
|
|
116
|
+
ads: [],
|
|
117
|
+
message: [],
|
|
118
|
+
highlight: ['generic', 'album', 'artist', 'playlist', 'radio', 'app'],
|
|
119
|
+
'deeplink-list': ['generic', 'deeplink'],
|
|
120
|
+
grid: [
|
|
121
|
+
'generic',
|
|
122
|
+
'album',
|
|
123
|
+
'artist',
|
|
124
|
+
'playlist',
|
|
125
|
+
'radio',
|
|
126
|
+
'channel',
|
|
127
|
+
'show',
|
|
128
|
+
'page',
|
|
129
|
+
'smarttracklist',
|
|
130
|
+
'flow',
|
|
131
|
+
'video-link',
|
|
132
|
+
],
|
|
133
|
+
slideshow: ['album', 'artist', 'playlist', 'radio', 'show', 'channel', 'video-link', 'external-link'],
|
|
134
|
+
'large-card': ['generic', 'album', 'artist', 'playlist', 'radio', 'show', 'external-link', 'video-link'],
|
|
135
|
+
'item-highlight': ['radio', 'app'],
|
|
136
|
+
'small-horizontal-grid': ['album', 'artist', 'playlist', 'radio', 'channel', 'show'],
|
|
137
|
+
'grid-preview-two': [
|
|
138
|
+
'generic',
|
|
139
|
+
'album',
|
|
140
|
+
'artist',
|
|
141
|
+
'playlist',
|
|
142
|
+
'radio',
|
|
143
|
+
'channel',
|
|
144
|
+
'show',
|
|
145
|
+
'page',
|
|
146
|
+
'smarttracklist',
|
|
147
|
+
'flow',
|
|
148
|
+
'video-link',
|
|
149
|
+
],
|
|
150
|
+
list: ['generic', 'album', 'artist', 'playlist', 'radio', 'show', 'video-link', 'channel', 'episode'],
|
|
151
|
+
'grid-preview-one': [
|
|
152
|
+
'generic',
|
|
153
|
+
'album',
|
|
154
|
+
'artist',
|
|
155
|
+
'playlist',
|
|
156
|
+
'radio',
|
|
157
|
+
'channel',
|
|
158
|
+
'show',
|
|
159
|
+
'page',
|
|
160
|
+
'smarttracklist',
|
|
161
|
+
'flow',
|
|
162
|
+
'video-link',
|
|
163
|
+
],
|
|
164
|
+
'horizontal-grid': [
|
|
165
|
+
'generic',
|
|
166
|
+
'album',
|
|
167
|
+
'artist',
|
|
168
|
+
'playlist',
|
|
169
|
+
'radio',
|
|
170
|
+
'channel',
|
|
171
|
+
'show',
|
|
172
|
+
'video-link',
|
|
173
|
+
'smarttracklist',
|
|
174
|
+
'flow',
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
lang: 'en',
|
|
178
|
+
timezone_offset: '6',
|
|
179
|
+
};
|
|
180
|
+
return await (0, request_1.requestGet)('app_page_get', { gateway_input }, page);
|
|
181
|
+
};
|
|
182
|
+
exports.getPlaylistChannel = getPlaylistChannel;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fast_lru_1 = __importDefault(require("../lib/fast-lru"));
|
|
7
|
+
// Expire cache in 60 minutes
|
|
8
|
+
const lru = new fast_lru_1.default({
|
|
9
|
+
maxSize: 1000,
|
|
10
|
+
ttl: 60 * 60000,
|
|
11
|
+
});
|
|
12
|
+
exports.default = lru;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./api"), exports);
|
|
18
|
+
__exportStar(require("./request"), exports);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make POST requests to deezer api
|
|
3
|
+
* @param {Object} body post body
|
|
4
|
+
* @param {String} method request method
|
|
5
|
+
*/
|
|
6
|
+
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
|
+
*/
|
|
12
|
+
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
|
+
*/
|
|
18
|
+
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
|
+
export declare const requestPublicApi: (slug: string) => Promise<any>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.requestPublicApi = exports.requestGet = exports.requestLight = exports.request = void 0;
|
|
7
|
+
const request_1 = __importDefault(require("../lib/request"));
|
|
8
|
+
const cache_1 = __importDefault(require("./cache"));
|
|
9
|
+
/**
|
|
10
|
+
* Make POST requests to deezer api
|
|
11
|
+
* @param {Object} body post body
|
|
12
|
+
* @param {String} method request method
|
|
13
|
+
*/
|
|
14
|
+
const request = async (body, method) => {
|
|
15
|
+
const cacheKey = method + ':' + Object.entries(body).join(':');
|
|
16
|
+
const cache = cache_1.default.get(cacheKey);
|
|
17
|
+
if (cache) {
|
|
18
|
+
return cache;
|
|
19
|
+
}
|
|
20
|
+
const { data: { error, results }, } = await request_1.default.post('/gateway.php', body, { params: { method } });
|
|
21
|
+
if (Object.keys(results).length > 0) {
|
|
22
|
+
cache_1.default.set(cacheKey, results);
|
|
23
|
+
return results;
|
|
24
|
+
}
|
|
25
|
+
const errorMessage = Object.entries(error).join(', ');
|
|
26
|
+
throw new Error(errorMessage);
|
|
27
|
+
};
|
|
28
|
+
exports.request = request;
|
|
29
|
+
/**
|
|
30
|
+
* Make POST requests to deezer api
|
|
31
|
+
* @param {Object} body post body
|
|
32
|
+
* @param {String} method request method
|
|
33
|
+
*/
|
|
34
|
+
const requestLight = async (body, method) => {
|
|
35
|
+
const cacheKey = method + ':' + Object.entries(body).join(':');
|
|
36
|
+
const cache = cache_1.default.get(cacheKey);
|
|
37
|
+
if (cache) {
|
|
38
|
+
return cache;
|
|
39
|
+
}
|
|
40
|
+
const { data: { error, results }, } = await request_1.default.post('https://www.deezer.com/ajax/gw-light.php', body, {
|
|
41
|
+
params: { method, api_version: '1.0' },
|
|
42
|
+
});
|
|
43
|
+
if (Object.keys(results).length > 0) {
|
|
44
|
+
cache_1.default.set(cacheKey, results);
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
const errorMessage = Object.entries(error).join(', ');
|
|
48
|
+
throw new Error(errorMessage);
|
|
49
|
+
};
|
|
50
|
+
exports.requestLight = requestLight;
|
|
51
|
+
/**
|
|
52
|
+
* Make GET requests to deezer public api
|
|
53
|
+
* @param {String} method request method
|
|
54
|
+
* @param {Object} params request parameters
|
|
55
|
+
*/
|
|
56
|
+
const requestGet = async (method, params = {}, key = 'get_request') => {
|
|
57
|
+
const cacheKey = method + key;
|
|
58
|
+
const cache = cache_1.default.get(cacheKey);
|
|
59
|
+
if (cache) {
|
|
60
|
+
return cache;
|
|
61
|
+
}
|
|
62
|
+
const { data: { error, results }, } = await request_1.default.get('/gateway.php', { params: { method, ...params } });
|
|
63
|
+
if (Object.keys(results).length > 0) {
|
|
64
|
+
cache_1.default.set(cacheKey, results);
|
|
65
|
+
return results;
|
|
66
|
+
}
|
|
67
|
+
const errorMessage = Object.entries(error).join(', ');
|
|
68
|
+
throw new Error(errorMessage);
|
|
69
|
+
};
|
|
70
|
+
exports.requestGet = requestGet;
|
|
71
|
+
/**
|
|
72
|
+
* Make GET requests to deezer public api
|
|
73
|
+
* @param {String} slug endpoint
|
|
74
|
+
*/
|
|
75
|
+
const requestPublicApi = async (slug) => {
|
|
76
|
+
const cache = cache_1.default.get(slug);
|
|
77
|
+
if (cache) {
|
|
78
|
+
return cache;
|
|
79
|
+
}
|
|
80
|
+
const { data } = await request_1.default.get('https://api.deezer.com' + slug);
|
|
81
|
+
if (data.error) {
|
|
82
|
+
const errorMessage = Object.entries(data.error).join(', ');
|
|
83
|
+
throw new Error(errorMessage);
|
|
84
|
+
}
|
|
85
|
+
cache_1.default.set(slug, data);
|
|
86
|
+
return data;
|
|
87
|
+
};
|
|
88
|
+
exports.requestPublicApi = requestPublicApi;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.upc2deezer = exports.isrc2deezer = void 0;
|
|
7
|
+
const delay_1 = __importDefault(require("delay"));
|
|
8
|
+
const api_1 = require("../api");
|
|
9
|
+
const http_1 = require("../lib/http");
|
|
10
|
+
const instance = new http_1.HttpClient({ baseURL: 'https://api.deezer.com/', timeout: 15000 });
|
|
11
|
+
const requestLookup = async (path) => {
|
|
12
|
+
const { data } = await instance.get(path);
|
|
13
|
+
if (data.error && data.error.code === 4) {
|
|
14
|
+
await delay_1.default.range(1000, 1500);
|
|
15
|
+
return await requestLookup(path);
|
|
16
|
+
}
|
|
17
|
+
return data;
|
|
18
|
+
};
|
|
19
|
+
const isrc2deezer = async (name, isrc) => {
|
|
20
|
+
if (!isrc) {
|
|
21
|
+
throw new Error('ISRC code not found for ' + name);
|
|
22
|
+
}
|
|
23
|
+
const data = await requestLookup('track/isrc:' + isrc);
|
|
24
|
+
if (data.error) {
|
|
25
|
+
throw new Error(`No match on deezer for ${name} (ISRC: ${isrc})`);
|
|
26
|
+
}
|
|
27
|
+
return await (0, api_1.getTrackInfo)(data.id);
|
|
28
|
+
};
|
|
29
|
+
exports.isrc2deezer = isrc2deezer;
|
|
30
|
+
const upc2deezer = async (name, upc) => {
|
|
31
|
+
if (!upc) {
|
|
32
|
+
throw new Error('UPC code not found for ' + name);
|
|
33
|
+
}
|
|
34
|
+
else if (upc.length > 12 && upc.startsWith('0')) {
|
|
35
|
+
upc = upc.slice(-12);
|
|
36
|
+
}
|
|
37
|
+
const data = await requestLookup('album/upc:' + upc);
|
|
38
|
+
if (data.error) {
|
|
39
|
+
throw new Error(`No match on deezer for ${name} (UPC: ${upc})`);
|
|
40
|
+
}
|
|
41
|
+
const albumInfo = await (0, api_1.getAlbumInfo)(data.id);
|
|
42
|
+
const albumTracks = await (0, api_1.getAlbumTracks)(data.id);
|
|
43
|
+
return [albumInfo, albumTracks.data];
|
|
44
|
+
};
|
|
45
|
+
exports.upc2deezer = upc2deezer;
|