gerdur 2.5.0 → 2.7.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 CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.7.0 - 2026-08-31
4
+
5
+ ### Added
6
+
7
+ - **`gerdur-core@^2.9.0`** — re-exports `downloadTrackBuffer` (download + decrypt
8
+ to a `Buffer`) and the low-level session client as `createCoreSession` /
9
+ `CoreSession` / `defaultSession` (for talking to Deezer directly or from
10
+ multiple accounts — gerdur's own `Session` stays the download orchestrator).
11
+ - **CLI `chart` / `chart:<genreId>`** — pick tracks from this week's Deezer chart
12
+ (optionally a genre) and download them. Headless-friendly.
13
+
14
+ ### Changed
15
+
16
+ - Gateway retries are bounded and downloads are session-aware (via
17
+ `gerdur-core@2.4`–`2.9`); `license_token` refreshes proactively.
18
+
19
+ ## 2.6.0 - 2026-08-31
20
+
21
+ ### Added
22
+
23
+ - **`gerdur-core@^2.6.0`** — re-exports the Flow / radios / library surface:
24
+ `getUserFlow`, `getUserFavoriteTracks` / `Albums` / `Artists`,
25
+ `getUserPlaylists`, `getUserRadios`, `getUserChartTracks`, `getRadios`,
26
+ `getRadioTracks`, `getRadioGenres` + their types.
27
+ - **`Session` methods**: `flow`, `favoriteTracks`, `favoriteAlbums`,
28
+ `favoriteArtists`, `playlists`, `userRadios`, `radios`, `radioTracks` — the
29
+ `userId` argument defaults to the logged-in user.
30
+ - **CLI `flow` / `flow:<userId>` / `radio:<id>`** — pick tracks from your (or
31
+ another user's) Flow, or a radio's current playlist, and download them.
32
+ Headless-friendly.
33
+
3
34
  ## 2.5.0 - 2026-08-31
4
35
 
5
36
  ### Changed
package/README.md CHANGED
@@ -159,8 +159,12 @@ When `gerdur` asks for a URL, a search term, or a prefixed query:
159
159
  | `search:artist:"daft punk" bpm_min:120` | advanced track search (see operators below) |
160
160
  | `isrc:GBDUW0000059` | download the exact track for an ISRC |
161
161
  | `upc:0724384960650` | download the album for a UPC / EAN barcode |
162
+ | `flow` | pick tracks from your Deezer **Flow** |
163
+ | `flow:2064440442` | pick tracks from another user's Flow |
164
+ | `radio:38305` | pick tracks from a radio's current playlist |
165
+ | `chart` / `chart:132` | pick tracks from this week's chart (optionally a genre) |
162
166
 
163
- `isrc:` and `upc:` also work in `--headless` mode (`-u isrc:…` / `-u upc:…`).
167
+ `isrc:` / `upc:` / `flow` / `radio:` also work in `--headless` mode (`-u flow`, ).
164
168
 
165
169
  ### From flags (works headless)
166
170
 
@@ -258,6 +262,9 @@ Session methods:
258
262
  - **browse** — `genres`, `chart`, `chartTracks`, `editorialSections`,
259
263
  `artistTopTracks`, `relatedArtists`, `artistAlbums`, `artistRadio`,
260
264
  `trackByISRC`, `albumByUPC`
265
+ - **flow / library** — `flow`, `favoriteTracks`, `favoriteAlbums`,
266
+ `favoriteArtists`, `playlists`, `userRadios`, `radios`, `radioTracks`
267
+ (the `userId` arg defaults to the logged-in user)
261
268
  - **user / download** — `getUser`, `getTrackBuffer`, `streamTrack`,
262
269
  `downloadTrack`, `downloadTracks`, `downloadUrl`, `trackPreview`, `downloadPreview`
263
270
 
@@ -319,10 +326,19 @@ or `createSession`):
319
326
  `getEditorialCharts`, `getArtistTopTracks`, `getRelatedArtists`,
320
327
  `getArtistAlbums`, `getArtistPlaylists`, `getArtistRadioTracks`,
321
328
  `getTrackByISRC`, `getAlbumByUPC`
329
+ - **Flow / library** — `getUserFlow`, `getUserFavoriteTracks`,
330
+ `getUserFavoriteAlbums`, `getUserFavoriteArtists`, `getUserPlaylists`,
331
+ `getUserRadios`, `getUserChartTracks`, `getRadios`, `getRadioTracks`,
332
+ `getRadioGenres`
322
333
  - **Download** — `getTrackDownloadUrl`, `resolveDownloadUrls`,
323
- `streamTrackDownload`, `createDecryptStream`, `getStream`, `getTrackPreview`,
324
- `downloadPreview`, `formatName`, `toFormat`, `DEEZER_FORMATS`
334
+ `streamTrackDownload`, `downloadTrackBuffer`, `createDecryptStream`, `getStream`,
335
+ `getTrackPreview`, `downloadPreview`, `formatName`, `toFormat`, `DEEZER_FORMATS`
325
336
  - **Errors** — `DeezerError` (`code` / `keys` / `retryable`), `GeoBlocked`
337
+ - **Low-level sessions** — `createCoreSession(arl)` / `CoreSession` /
338
+ `defaultSession` from `gerdur-core`: an isolated client (its own `arl`, cache,
339
+ `license_token`) with `getTrackInfo` / `searchMusic` / `getTrackBuffer` / … for
340
+ talking to Deezer directly or from multiple accounts. gerdur's own
341
+ `createSession` / `Session` (above) is the higher-level download orchestrator.
326
342
 
327
343
  ### Auth & config helpers
328
344
 
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerdur",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "The crucial streaming module for dabox systems.",
5
5
  "author": "Christian",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -48,7 +48,7 @@
48
48
  "adm-zip": "^0.5.16",
49
49
  "chalk": "^4.1.2",
50
50
  "commander": "^9.5.0",
51
- "gerdur-core": "^2.5.0",
51
+ "gerdur-core": "^2.9.0",
52
52
  "dot-prop": "^6.0.1",
53
53
  "got": "^11.8.6",
54
54
  "gradient-string": "^2.0.2",
@@ -111,18 +111,14 @@ const stampVersion = (t) => {
111
111
  * picks into download-ready gw tracks via `getTrackInfo`. Returns `null` when
112
112
  * nothing was matched or selected.
113
113
  */
114
- const resolveAdvancedSearch = async (filters) => {
115
- const limit = toFiniteNumber(options.searchLimit) ?? 50;
116
- const { data: results, query, usedFallback } = await (0, search_1.searchAdvancedTracks)(filters, { limit });
117
- if (!query) {
118
- return null;
119
- }
120
- console.log(signale_1.default.info(`Searching Deezer for: ${chalk_1.default.cyan(query)}`));
121
- if (usedFallback) {
122
- console.log(signale_1.default.note('No matches for the operators — retried as a plain-text search.'));
123
- }
114
+ /**
115
+ * Given a list of public-API track objects (from search / flow / a radio), let
116
+ * the user pick (unless headless) and hydrate the picks into download-ready gw
117
+ * tracks via `getTrackInfo`.
118
+ */
119
+ const pickAndHydrate = async (results, id) => {
124
120
  if (!results.length) {
125
- console.log(signale_1.default.warn('No tracks matched that search.'));
121
+ console.log(signale_1.default.warn('Nothing to download.'));
126
122
  return null;
127
123
  }
128
124
  let picks = results;
@@ -131,7 +127,7 @@ const resolveAdvancedSearch = async (filters) => {
131
127
  {
132
128
  type: 'multiselect',
133
129
  name: 'items',
134
- message: `Select tracks to download. ${results.length} matched.`,
130
+ message: `Select tracks to download. ${results.length} available.`,
135
131
  choices: results.map((r) => ({
136
132
  title: `${r.title} — ${r.artist?.name ?? 'Unknown'}`,
137
133
  value: r,
@@ -151,7 +147,19 @@ const resolveAdvancedSearch = async (filters) => {
151
147
  console.log(signale_1.default.warn('None of the selected tracks could be resolved.'));
152
148
  return null;
153
149
  }
154
- return { info: { type: 'track', id: query }, linktype: 'track', linkinfo: {}, tracks };
150
+ return { info: { type: 'track', id }, linktype: 'track', linkinfo: {}, tracks };
151
+ };
152
+ const resolveAdvancedSearch = async (filters) => {
153
+ const limit = toFiniteNumber(options.searchLimit) ?? 50;
154
+ const { data: results, query, usedFallback } = await (0, search_1.searchAdvancedTracks)(filters, { limit });
155
+ if (!query) {
156
+ return null;
157
+ }
158
+ console.log(signale_1.default.info(`Searching Deezer for: ${chalk_1.default.cyan(query)}`));
159
+ if (usedFallback) {
160
+ console.log(signale_1.default.note('No matches for the operators — retried as a plain-text search.'));
161
+ }
162
+ return pickAndHydrate(results, query);
155
163
  };
156
164
  /**
157
165
  * `--preview`: fetch the 30-second clip for each selected track and write it as
@@ -228,7 +236,7 @@ const startDownload = async (saveLayout, url, skipPrompt) => {
228
236
  {
229
237
  type: 'text',
230
238
  name: 'query',
231
- message: 'Enter a URL, a search term, or a `search:` / `isrc:` / `upc:` query:',
239
+ message: 'Enter a URL, a search term, or `search:` / `isrc:` / `upc:` / `flow` / `radio:<id>` / `chart[:<genre>]`:',
232
240
  validate: (value) => (value ? true : false),
233
241
  },
234
242
  ], { onCancel });
@@ -260,6 +268,36 @@ const startDownload = async (saveLayout, url, skipPrompt) => {
260
268
  console.log(signale_1.default.info(`UPC ${code} → ${found.title} (${found.nb_tracks} tracks)`));
261
269
  url = `https://www.deezer.com/album/${found.id}`;
262
270
  }
271
+ // `flow:` / `flow:<userId>` — download from Deezer Flow.
272
+ if (!searchData && url && (url === 'flow' || url.startsWith('flow:'))) {
273
+ const uid = url.includes(':') ? url.slice('flow:'.length).trim() : (await (0, gerdur_core_1.getUser)()).USER_ID;
274
+ console.log(signale_1.default.info(`Fetching Flow for user ${uid}…`));
275
+ const { data } = await (0, gerdur_core_1.getUserFlow)(uid);
276
+ searchData = await pickAndHydrate(data, `flow:${uid}`);
277
+ if (!searchData) {
278
+ throw new Error('Flow returned no tracks (is the profile public?).');
279
+ }
280
+ }
281
+ // `radio:<id>` — download a radio's current tracklist.
282
+ if (!searchData && url && url.startsWith('radio:')) {
283
+ const rid = url.slice('radio:'.length).trim();
284
+ console.log(signale_1.default.info(`Fetching radio ${rid}…`));
285
+ const { data } = await (0, gerdur_core_1.getRadioTracks)(rid);
286
+ searchData = await pickAndHydrate(data, `radio:${rid}`);
287
+ if (!searchData) {
288
+ throw new Error(`Radio ${rid} returned no tracks.`);
289
+ }
290
+ }
291
+ // `chart` / `chart:<genreId>` — download from Deezer's weekly chart.
292
+ if (!searchData && url && (url === 'chart' || url.startsWith('chart:'))) {
293
+ const genreId = url.includes(':') ? url.slice('chart:'.length).trim() : 0;
294
+ console.log(signale_1.default.info(`Fetching chart${genreId ? ` for genre ${genreId}` : ''}…`));
295
+ const { data } = await (0, gerdur_core_1.getChartTracks)(genreId, toFiniteNumber(options.searchLimit) ?? 50);
296
+ searchData = await pickAndHydrate(data, `chart:${genreId}`);
297
+ if (!searchData) {
298
+ throw new Error('Chart returned no tracks.');
299
+ }
300
+ }
263
301
  if (!searchData && !url.match(urlRegex)) {
264
302
  if (options.headless) {
265
303
  throw new Error('Please provide a valid URL. Unknown URL: ' + url);
@@ -56,10 +56,12 @@ export declare class LoginError extends Error {
56
56
  export declare const getArl: (email: string, password: string) => Promise<string>;
57
57
  export { createSession, Session } from './lib/session';
58
58
  export type { SessionOptions, DownloadTracksOptions, SearchType } from './lib/session';
59
+ export { createSession as createCoreSession, Session as CoreSession, defaultSession } from 'gerdur-core';
60
+ export type { SessionUserData } from 'gerdur-core';
59
61
  export { getTrackBuffer, getTaggedTrack, downloadTrackToFile } from './lib/api-download';
60
62
  export type { Quality, GetTrackBufferOptions, DownloadTrackOptions, DownloadResult } from './lib/api-download';
61
63
  export { default as Config, globalConfigPath, resolveConfigFile } from './lib/config';
62
- export { initDeezerApi, parseInfo, searchMusic, searchPublicApi, searchTracks, searchAlbums, searchArtists, searchPlaylists, buildAdvancedQuery, suggest, getGenres, getChart, getChartTracks, getGenreArtists, getEditorialList, getEditorialReleases, getEditorialSelection, getEditorialCharts, getArtistTopTracks, getRelatedArtists, getArtistAlbums, getArtistPlaylists, getArtistRadioTracks, getTrackByISRC, getAlbumByUPC, getTrackPreview, downloadPreview, formatName, toFormat, DEEZER_FORMATS, getUser, getTrackInfo, getAlbumInfo, getAlbumTracks, getPlaylistInfo, getPlaylistTracks, getArtistInfo, getDiscography, getLyrics, getTrackDownloadUrl, resolveDownloadUrls, streamTrackDownload, createDecryptStream, getStream, addTrackTags, getRichAlbum, normalizeContributors, toLrc, GeoBlocked, DeezerError, } from 'gerdur-core';
64
+ export { initDeezerApi, parseInfo, searchMusic, searchPublicApi, searchTracks, searchAlbums, searchArtists, searchPlaylists, buildAdvancedQuery, suggest, getGenres, getChart, getChartTracks, getGenreArtists, getEditorialList, getEditorialReleases, getEditorialSelection, getEditorialCharts, getArtistTopTracks, getRelatedArtists, getArtistAlbums, getArtistPlaylists, getArtistRadioTracks, getUserFlow, getUserFavoriteTracks, getUserFavoriteAlbums, getUserFavoriteArtists, getUserPlaylists, getUserRadios, getUserChartTracks, getRadios, getRadioTracks, getRadioGenres, getTrackByISRC, getAlbumByUPC, getTrackPreview, downloadPreview, formatName, toFormat, DEEZER_FORMATS, getUser, getTrackInfo, getAlbumInfo, getAlbumTracks, getPlaylistInfo, getPlaylistTracks, getArtistInfo, getDiscography, getLyrics, getTrackDownloadUrl, resolveDownloadUrls, streamTrackDownload, downloadTrackBuffer, createDecryptStream, getStream, addTrackTags, getRichAlbum, normalizeContributors, toLrc, GeoBlocked, DeezerError, } from 'gerdur-core';
63
65
  export type { AddTrackTagsOptions, TaggedTrack, TrackTagModel, RichAlbum, ResolvedUrl, NormalizedContributors, } from 'gerdur-core';
64
- export type { advancedSearchFilters, searchOrder, searchEntity, publicApiSearchOptions, publicApiSearchResponse, searchResultTrack, searchResultAlbum, searchResultArtist, searchResultPlaylist, suggestResult, publicApiList, chartType, chartTrack, chartAlbum, chartArtist, chartPlaylist, chartPodcast, genreType, editorialType, artistAlbumResult, } from 'gerdur-core/types';
66
+ export type { advancedSearchFilters, searchOrder, searchEntity, publicApiSearchOptions, publicApiSearchResponse, searchResultTrack, searchResultAlbum, searchResultArtist, searchResultPlaylist, suggestResult, publicApiList, chartType, chartTrack, chartAlbum, chartArtist, chartPlaylist, chartPodcast, genreType, editorialType, artistAlbumResult, userFavoriteTrack, userFavoriteAlbum, userFavoriteArtist, userPlaylistResult, radioResult, radioGenre, } from 'gerdur-core/types';
65
67
  export type { Quality as MediaFormat, DeezerFormat, TrackPreview, StreamTrackOptions, TrackStream, StreamResponse, DeezerErrorPayload, } from 'gerdur-core';
package/dist/src/index.js CHANGED
@@ -33,8 +33,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
33
33
  return (mod && mod.__esModule) ? mod : { "default": mod };
34
34
  };
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getLyrics = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getTrackInfo = exports.getUser = exports.DEEZER_FORMATS = exports.toFormat = exports.formatName = exports.downloadPreview = exports.getTrackPreview = exports.getAlbumByUPC = exports.getTrackByISRC = exports.getArtistRadioTracks = exports.getArtistPlaylists = exports.getArtistAlbums = exports.getRelatedArtists = exports.getArtistTopTracks = exports.getEditorialCharts = exports.getEditorialSelection = exports.getEditorialReleases = exports.getEditorialList = exports.getGenreArtists = exports.getChartTracks = exports.getChart = exports.getGenres = exports.suggest = exports.buildAdvancedQuery = exports.searchPlaylists = exports.searchArtists = exports.searchAlbums = exports.searchTracks = exports.searchPublicApi = exports.searchMusic = exports.parseInfo = exports.initDeezerApi = exports.resolveConfigFile = exports.globalConfigPath = exports.Config = exports.downloadTrackToFile = exports.getTaggedTrack = exports.getTrackBuffer = exports.Session = exports.createSession = exports.getArl = exports.LoginError = exports.loginWithEmail = void 0;
37
- exports.DeezerError = exports.GeoBlocked = exports.toLrc = exports.normalizeContributors = exports.getRichAlbum = exports.addTrackTags = exports.getStream = exports.createDecryptStream = exports.streamTrackDownload = exports.resolveDownloadUrls = exports.getTrackDownloadUrl = void 0;
36
+ exports.getTrackPreview = exports.getAlbumByUPC = exports.getTrackByISRC = exports.getRadioGenres = exports.getRadioTracks = exports.getRadios = exports.getUserChartTracks = exports.getUserRadios = exports.getUserPlaylists = exports.getUserFavoriteArtists = exports.getUserFavoriteAlbums = exports.getUserFavoriteTracks = exports.getUserFlow = exports.getArtistRadioTracks = exports.getArtistPlaylists = exports.getArtistAlbums = exports.getRelatedArtists = exports.getArtistTopTracks = exports.getEditorialCharts = exports.getEditorialSelection = exports.getEditorialReleases = exports.getEditorialList = exports.getGenreArtists = exports.getChartTracks = exports.getChart = exports.getGenres = exports.suggest = exports.buildAdvancedQuery = exports.searchPlaylists = exports.searchArtists = exports.searchAlbums = exports.searchTracks = exports.searchPublicApi = exports.searchMusic = exports.parseInfo = exports.initDeezerApi = exports.resolveConfigFile = exports.globalConfigPath = exports.Config = exports.downloadTrackToFile = exports.getTaggedTrack = exports.getTrackBuffer = exports.defaultSession = exports.CoreSession = exports.createCoreSession = exports.Session = exports.createSession = exports.getArl = exports.LoginError = exports.loginWithEmail = void 0;
37
+ exports.DeezerError = exports.GeoBlocked = exports.toLrc = exports.normalizeContributors = exports.getRichAlbum = exports.addTrackTags = exports.getStream = exports.createDecryptStream = exports.downloadTrackBuffer = exports.streamTrackDownload = exports.resolveDownloadUrls = exports.getTrackDownloadUrl = exports.getLyrics = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getTrackInfo = exports.getUser = exports.DEEZER_FORMATS = exports.toFormat = exports.formatName = exports.downloadPreview = void 0;
38
38
  // ─── Authentication ────────────────────────────────────────────────────────
39
39
  const email_login_1 = require("./lib/email-login");
40
40
  Object.defineProperty(exports, "loginWithEmail", { enumerable: true, get: function () { return email_login_1.loginWithEmail; } });
@@ -72,6 +72,13 @@ exports.getArl = getArl;
72
72
  var session_1 = require("./lib/session");
73
73
  Object.defineProperty(exports, "createSession", { enumerable: true, get: function () { return session_1.createSession; } });
74
74
  Object.defineProperty(exports, "Session", { enumerable: true, get: function () { return session_1.Session; } });
75
+ // `gerdur-core`'s low-level session — an isolated client (its own `arl`, cache,
76
+ // `license_token`) for talking to Deezer directly / from multiple accounts.
77
+ // gerdur's `Session` above is the higher-level download-orchestration one.
78
+ var gerdur_core_1 = require("gerdur-core");
79
+ Object.defineProperty(exports, "createCoreSession", { enumerable: true, get: function () { return gerdur_core_1.createSession; } });
80
+ Object.defineProperty(exports, "CoreSession", { enumerable: true, get: function () { return gerdur_core_1.Session; } });
81
+ Object.defineProperty(exports, "defaultSession", { enumerable: true, get: function () { return gerdur_core_1.defaultSession; } });
75
82
  // ─── Download primitives ─────────────────────────────────────────────────────
76
83
  var api_download_1 = require("./lib/api-download");
77
84
  Object.defineProperty(exports, "getTrackBuffer", { enumerable: true, get: function () { return api_download_1.getTrackBuffer; } });
@@ -86,54 +93,65 @@ Object.defineProperty(exports, "resolveConfigFile", { enumerable: true, get: fun
86
93
  // ─── Re-exported core query functions ────────────────────────────────────────
87
94
  // Convenience re-exports so consumers don't need `gerdur-core` directly.
88
95
  // After `initDeezerApi(arl)` (or `createSession`) these are ready to use.
89
- var gerdur_core_1 = require("gerdur-core");
90
- Object.defineProperty(exports, "initDeezerApi", { enumerable: true, get: function () { return gerdur_core_1.initDeezerApi; } });
91
- Object.defineProperty(exports, "parseInfo", { enumerable: true, get: function () { return gerdur_core_1.parseInfo; } });
92
- Object.defineProperty(exports, "searchMusic", { enumerable: true, get: function () { return gerdur_core_1.searchMusic; } });
93
- Object.defineProperty(exports, "searchPublicApi", { enumerable: true, get: function () { return gerdur_core_1.searchPublicApi; } });
94
- Object.defineProperty(exports, "searchTracks", { enumerable: true, get: function () { return gerdur_core_1.searchTracks; } });
95
- Object.defineProperty(exports, "searchAlbums", { enumerable: true, get: function () { return gerdur_core_1.searchAlbums; } });
96
- Object.defineProperty(exports, "searchArtists", { enumerable: true, get: function () { return gerdur_core_1.searchArtists; } });
97
- Object.defineProperty(exports, "searchPlaylists", { enumerable: true, get: function () { return gerdur_core_1.searchPlaylists; } });
98
- Object.defineProperty(exports, "buildAdvancedQuery", { enumerable: true, get: function () { return gerdur_core_1.buildAdvancedQuery; } });
99
- Object.defineProperty(exports, "suggest", { enumerable: true, get: function () { return gerdur_core_1.suggest; } });
100
- Object.defineProperty(exports, "getGenres", { enumerable: true, get: function () { return gerdur_core_1.getGenres; } });
101
- Object.defineProperty(exports, "getChart", { enumerable: true, get: function () { return gerdur_core_1.getChart; } });
102
- Object.defineProperty(exports, "getChartTracks", { enumerable: true, get: function () { return gerdur_core_1.getChartTracks; } });
103
- Object.defineProperty(exports, "getGenreArtists", { enumerable: true, get: function () { return gerdur_core_1.getGenreArtists; } });
104
- Object.defineProperty(exports, "getEditorialList", { enumerable: true, get: function () { return gerdur_core_1.getEditorialList; } });
105
- Object.defineProperty(exports, "getEditorialReleases", { enumerable: true, get: function () { return gerdur_core_1.getEditorialReleases; } });
106
- Object.defineProperty(exports, "getEditorialSelection", { enumerable: true, get: function () { return gerdur_core_1.getEditorialSelection; } });
107
- Object.defineProperty(exports, "getEditorialCharts", { enumerable: true, get: function () { return gerdur_core_1.getEditorialCharts; } });
108
- Object.defineProperty(exports, "getArtistTopTracks", { enumerable: true, get: function () { return gerdur_core_1.getArtistTopTracks; } });
109
- Object.defineProperty(exports, "getRelatedArtists", { enumerable: true, get: function () { return gerdur_core_1.getRelatedArtists; } });
110
- Object.defineProperty(exports, "getArtistAlbums", { enumerable: true, get: function () { return gerdur_core_1.getArtistAlbums; } });
111
- Object.defineProperty(exports, "getArtistPlaylists", { enumerable: true, get: function () { return gerdur_core_1.getArtistPlaylists; } });
112
- Object.defineProperty(exports, "getArtistRadioTracks", { enumerable: true, get: function () { return gerdur_core_1.getArtistRadioTracks; } });
113
- Object.defineProperty(exports, "getTrackByISRC", { enumerable: true, get: function () { return gerdur_core_1.getTrackByISRC; } });
114
- Object.defineProperty(exports, "getAlbumByUPC", { enumerable: true, get: function () { return gerdur_core_1.getAlbumByUPC; } });
115
- Object.defineProperty(exports, "getTrackPreview", { enumerable: true, get: function () { return gerdur_core_1.getTrackPreview; } });
116
- Object.defineProperty(exports, "downloadPreview", { enumerable: true, get: function () { return gerdur_core_1.downloadPreview; } });
117
- Object.defineProperty(exports, "formatName", { enumerable: true, get: function () { return gerdur_core_1.formatName; } });
118
- Object.defineProperty(exports, "toFormat", { enumerable: true, get: function () { return gerdur_core_1.toFormat; } });
119
- Object.defineProperty(exports, "DEEZER_FORMATS", { enumerable: true, get: function () { return gerdur_core_1.DEEZER_FORMATS; } });
120
- Object.defineProperty(exports, "getUser", { enumerable: true, get: function () { return gerdur_core_1.getUser; } });
121
- Object.defineProperty(exports, "getTrackInfo", { enumerable: true, get: function () { return gerdur_core_1.getTrackInfo; } });
122
- Object.defineProperty(exports, "getAlbumInfo", { enumerable: true, get: function () { return gerdur_core_1.getAlbumInfo; } });
123
- Object.defineProperty(exports, "getAlbumTracks", { enumerable: true, get: function () { return gerdur_core_1.getAlbumTracks; } });
124
- Object.defineProperty(exports, "getPlaylistInfo", { enumerable: true, get: function () { return gerdur_core_1.getPlaylistInfo; } });
125
- Object.defineProperty(exports, "getPlaylistTracks", { enumerable: true, get: function () { return gerdur_core_1.getPlaylistTracks; } });
126
- Object.defineProperty(exports, "getArtistInfo", { enumerable: true, get: function () { return gerdur_core_1.getArtistInfo; } });
127
- Object.defineProperty(exports, "getDiscography", { enumerable: true, get: function () { return gerdur_core_1.getDiscography; } });
128
- Object.defineProperty(exports, "getLyrics", { enumerable: true, get: function () { return gerdur_core_1.getLyrics; } });
129
- Object.defineProperty(exports, "getTrackDownloadUrl", { enumerable: true, get: function () { return gerdur_core_1.getTrackDownloadUrl; } });
130
- Object.defineProperty(exports, "resolveDownloadUrls", { enumerable: true, get: function () { return gerdur_core_1.resolveDownloadUrls; } });
131
- Object.defineProperty(exports, "streamTrackDownload", { enumerable: true, get: function () { return gerdur_core_1.streamTrackDownload; } });
132
- Object.defineProperty(exports, "createDecryptStream", { enumerable: true, get: function () { return gerdur_core_1.createDecryptStream; } });
133
- Object.defineProperty(exports, "getStream", { enumerable: true, get: function () { return gerdur_core_1.getStream; } });
134
- Object.defineProperty(exports, "addTrackTags", { enumerable: true, get: function () { return gerdur_core_1.addTrackTags; } });
135
- Object.defineProperty(exports, "getRichAlbum", { enumerable: true, get: function () { return gerdur_core_1.getRichAlbum; } });
136
- Object.defineProperty(exports, "normalizeContributors", { enumerable: true, get: function () { return gerdur_core_1.normalizeContributors; } });
137
- Object.defineProperty(exports, "toLrc", { enumerable: true, get: function () { return gerdur_core_1.toLrc; } });
138
- Object.defineProperty(exports, "GeoBlocked", { enumerable: true, get: function () { return gerdur_core_1.GeoBlocked; } });
139
- Object.defineProperty(exports, "DeezerError", { enumerable: true, get: function () { return gerdur_core_1.DeezerError; } });
96
+ var gerdur_core_2 = require("gerdur-core");
97
+ Object.defineProperty(exports, "initDeezerApi", { enumerable: true, get: function () { return gerdur_core_2.initDeezerApi; } });
98
+ Object.defineProperty(exports, "parseInfo", { enumerable: true, get: function () { return gerdur_core_2.parseInfo; } });
99
+ Object.defineProperty(exports, "searchMusic", { enumerable: true, get: function () { return gerdur_core_2.searchMusic; } });
100
+ Object.defineProperty(exports, "searchPublicApi", { enumerable: true, get: function () { return gerdur_core_2.searchPublicApi; } });
101
+ Object.defineProperty(exports, "searchTracks", { enumerable: true, get: function () { return gerdur_core_2.searchTracks; } });
102
+ Object.defineProperty(exports, "searchAlbums", { enumerable: true, get: function () { return gerdur_core_2.searchAlbums; } });
103
+ Object.defineProperty(exports, "searchArtists", { enumerable: true, get: function () { return gerdur_core_2.searchArtists; } });
104
+ Object.defineProperty(exports, "searchPlaylists", { enumerable: true, get: function () { return gerdur_core_2.searchPlaylists; } });
105
+ Object.defineProperty(exports, "buildAdvancedQuery", { enumerable: true, get: function () { return gerdur_core_2.buildAdvancedQuery; } });
106
+ Object.defineProperty(exports, "suggest", { enumerable: true, get: function () { return gerdur_core_2.suggest; } });
107
+ Object.defineProperty(exports, "getGenres", { enumerable: true, get: function () { return gerdur_core_2.getGenres; } });
108
+ Object.defineProperty(exports, "getChart", { enumerable: true, get: function () { return gerdur_core_2.getChart; } });
109
+ Object.defineProperty(exports, "getChartTracks", { enumerable: true, get: function () { return gerdur_core_2.getChartTracks; } });
110
+ Object.defineProperty(exports, "getGenreArtists", { enumerable: true, get: function () { return gerdur_core_2.getGenreArtists; } });
111
+ Object.defineProperty(exports, "getEditorialList", { enumerable: true, get: function () { return gerdur_core_2.getEditorialList; } });
112
+ Object.defineProperty(exports, "getEditorialReleases", { enumerable: true, get: function () { return gerdur_core_2.getEditorialReleases; } });
113
+ Object.defineProperty(exports, "getEditorialSelection", { enumerable: true, get: function () { return gerdur_core_2.getEditorialSelection; } });
114
+ Object.defineProperty(exports, "getEditorialCharts", { enumerable: true, get: function () { return gerdur_core_2.getEditorialCharts; } });
115
+ Object.defineProperty(exports, "getArtistTopTracks", { enumerable: true, get: function () { return gerdur_core_2.getArtistTopTracks; } });
116
+ Object.defineProperty(exports, "getRelatedArtists", { enumerable: true, get: function () { return gerdur_core_2.getRelatedArtists; } });
117
+ Object.defineProperty(exports, "getArtistAlbums", { enumerable: true, get: function () { return gerdur_core_2.getArtistAlbums; } });
118
+ Object.defineProperty(exports, "getArtistPlaylists", { enumerable: true, get: function () { return gerdur_core_2.getArtistPlaylists; } });
119
+ Object.defineProperty(exports, "getArtistRadioTracks", { enumerable: true, get: function () { return gerdur_core_2.getArtistRadioTracks; } });
120
+ Object.defineProperty(exports, "getUserFlow", { enumerable: true, get: function () { return gerdur_core_2.getUserFlow; } });
121
+ Object.defineProperty(exports, "getUserFavoriteTracks", { enumerable: true, get: function () { return gerdur_core_2.getUserFavoriteTracks; } });
122
+ Object.defineProperty(exports, "getUserFavoriteAlbums", { enumerable: true, get: function () { return gerdur_core_2.getUserFavoriteAlbums; } });
123
+ Object.defineProperty(exports, "getUserFavoriteArtists", { enumerable: true, get: function () { return gerdur_core_2.getUserFavoriteArtists; } });
124
+ Object.defineProperty(exports, "getUserPlaylists", { enumerable: true, get: function () { return gerdur_core_2.getUserPlaylists; } });
125
+ Object.defineProperty(exports, "getUserRadios", { enumerable: true, get: function () { return gerdur_core_2.getUserRadios; } });
126
+ Object.defineProperty(exports, "getUserChartTracks", { enumerable: true, get: function () { return gerdur_core_2.getUserChartTracks; } });
127
+ Object.defineProperty(exports, "getRadios", { enumerable: true, get: function () { return gerdur_core_2.getRadios; } });
128
+ Object.defineProperty(exports, "getRadioTracks", { enumerable: true, get: function () { return gerdur_core_2.getRadioTracks; } });
129
+ Object.defineProperty(exports, "getRadioGenres", { enumerable: true, get: function () { return gerdur_core_2.getRadioGenres; } });
130
+ Object.defineProperty(exports, "getTrackByISRC", { enumerable: true, get: function () { return gerdur_core_2.getTrackByISRC; } });
131
+ Object.defineProperty(exports, "getAlbumByUPC", { enumerable: true, get: function () { return gerdur_core_2.getAlbumByUPC; } });
132
+ Object.defineProperty(exports, "getTrackPreview", { enumerable: true, get: function () { return gerdur_core_2.getTrackPreview; } });
133
+ Object.defineProperty(exports, "downloadPreview", { enumerable: true, get: function () { return gerdur_core_2.downloadPreview; } });
134
+ Object.defineProperty(exports, "formatName", { enumerable: true, get: function () { return gerdur_core_2.formatName; } });
135
+ Object.defineProperty(exports, "toFormat", { enumerable: true, get: function () { return gerdur_core_2.toFormat; } });
136
+ Object.defineProperty(exports, "DEEZER_FORMATS", { enumerable: true, get: function () { return gerdur_core_2.DEEZER_FORMATS; } });
137
+ Object.defineProperty(exports, "getUser", { enumerable: true, get: function () { return gerdur_core_2.getUser; } });
138
+ Object.defineProperty(exports, "getTrackInfo", { enumerable: true, get: function () { return gerdur_core_2.getTrackInfo; } });
139
+ Object.defineProperty(exports, "getAlbumInfo", { enumerable: true, get: function () { return gerdur_core_2.getAlbumInfo; } });
140
+ Object.defineProperty(exports, "getAlbumTracks", { enumerable: true, get: function () { return gerdur_core_2.getAlbumTracks; } });
141
+ Object.defineProperty(exports, "getPlaylistInfo", { enumerable: true, get: function () { return gerdur_core_2.getPlaylistInfo; } });
142
+ Object.defineProperty(exports, "getPlaylistTracks", { enumerable: true, get: function () { return gerdur_core_2.getPlaylistTracks; } });
143
+ Object.defineProperty(exports, "getArtistInfo", { enumerable: true, get: function () { return gerdur_core_2.getArtistInfo; } });
144
+ Object.defineProperty(exports, "getDiscography", { enumerable: true, get: function () { return gerdur_core_2.getDiscography; } });
145
+ Object.defineProperty(exports, "getLyrics", { enumerable: true, get: function () { return gerdur_core_2.getLyrics; } });
146
+ Object.defineProperty(exports, "getTrackDownloadUrl", { enumerable: true, get: function () { return gerdur_core_2.getTrackDownloadUrl; } });
147
+ Object.defineProperty(exports, "resolveDownloadUrls", { enumerable: true, get: function () { return gerdur_core_2.resolveDownloadUrls; } });
148
+ Object.defineProperty(exports, "streamTrackDownload", { enumerable: true, get: function () { return gerdur_core_2.streamTrackDownload; } });
149
+ Object.defineProperty(exports, "downloadTrackBuffer", { enumerable: true, get: function () { return gerdur_core_2.downloadTrackBuffer; } });
150
+ Object.defineProperty(exports, "createDecryptStream", { enumerable: true, get: function () { return gerdur_core_2.createDecryptStream; } });
151
+ Object.defineProperty(exports, "getStream", { enumerable: true, get: function () { return gerdur_core_2.getStream; } });
152
+ Object.defineProperty(exports, "addTrackTags", { enumerable: true, get: function () { return gerdur_core_2.addTrackTags; } });
153
+ Object.defineProperty(exports, "getRichAlbum", { enumerable: true, get: function () { return gerdur_core_2.getRichAlbum; } });
154
+ Object.defineProperty(exports, "normalizeContributors", { enumerable: true, get: function () { return gerdur_core_2.normalizeContributors; } });
155
+ Object.defineProperty(exports, "toLrc", { enumerable: true, get: function () { return gerdur_core_2.toLrc; } });
156
+ Object.defineProperty(exports, "GeoBlocked", { enumerable: true, get: function () { return gerdur_core_2.GeoBlocked; } });
157
+ Object.defineProperty(exports, "DeezerError", { enumerable: true, get: function () { return gerdur_core_2.DeezerError; } });
@@ -2,7 +2,7 @@
2
2
  import { parseInfo, searchMusic } from 'gerdur-core';
3
3
  import type { AdvancedSearchOptions } from './search';
4
4
  import type { Quality, DownloadTrackOptions, DownloadResult } from './api-download';
5
- import type { trackType, userType, advancedSearchFilters, publicApiSearchResponse, searchResultTrack, suggestResult, chartType, genreType, editorialType, artistAlbumResult, searchResultArtist, publicApiList, trackTypePublicApi, albumTypePublicApi } from 'gerdur-core/types';
5
+ import type { trackType, userType, advancedSearchFilters, publicApiSearchResponse, searchResultTrack, suggestResult, chartType, genreType, editorialType, artistAlbumResult, searchResultArtist, publicApiList, trackTypePublicApi, albumTypePublicApi, userFavoriteTrack, userFavoriteAlbum, userFavoriteArtist, userPlaylistResult, radioResult } from 'gerdur-core/types';
6
6
  import type { TrackPreview, StreamTrackOptions, TrackStream } from 'gerdur-core';
7
7
  /** Search result categories accepted by {@link Session.search}. */
8
8
  export type SearchType = 'ALBUM' | 'ARTIST' | 'TRACK' | 'PLAYLIST' | 'RADIO' | 'SHOW' | 'USER' | 'LIVESTREAM' | 'CHANNEL';
@@ -39,7 +39,10 @@ export declare class Session {
39
39
  /** The arl in use for this session. */
40
40
  readonly arl: string;
41
41
  private concurrency;
42
+ private userId?;
42
43
  private constructor();
44
+ /** The logged-in user's numeric id (cached). Used by the no-arg `flow` / `favorite*` methods. */
45
+ private resolveUserId;
43
46
  /**
44
47
  * Log in and return a ready-to-use session. Accepts either an `arl` or
45
48
  * `email`+`password` (which are exchanged for an arl via Deezer's OAuth flow).
@@ -86,6 +89,22 @@ export declare class Session {
86
89
  trackByISRC(isrc: string): Promise<trackTypePublicApi>;
87
90
  /** Resolve a UPC/EAN barcode to the public-API album (with its `tracks`). */
88
91
  albumByUPC(upc: string): Promise<albumTypePublicApi>;
92
+ /** Deezer **Flow** — the endless personalised mix, as tracks. */
93
+ flow(userId?: string | number, limit?: number): Promise<publicApiList<searchResultTrack>>;
94
+ /** A user's favourite (loved) tracks, newest first (each with `time_add`). */
95
+ favoriteTracks(userId?: string | number, limit?: number): Promise<publicApiList<userFavoriteTrack>>;
96
+ /** A user's favourite albums. */
97
+ favoriteAlbums(userId?: string | number, limit?: number): Promise<publicApiList<userFavoriteAlbum>>;
98
+ /** A user's favourite artists. */
99
+ favoriteArtists(userId?: string | number, limit?: number): Promise<publicApiList<userFavoriteArtist>>;
100
+ /** A user's own + followed playlists. */
101
+ playlists(userId?: string | number, limit?: number): Promise<publicApiList<userPlaylistResult>>;
102
+ /** The radios a user has favourited. */
103
+ userRadios(userId?: string | number): Promise<publicApiList<radioResult>>;
104
+ /** Deezer's curated radio list. */
105
+ radios(): Promise<publicApiList<radioResult>>;
106
+ /** A radio's current tracklist — a ready-to-play (public-API) source. */
107
+ radioTracks(radioId: string | number): Promise<publicApiList<searchResultTrack>>;
89
108
  /** The 30-second preview clip URL for a track (plain MP3 — no licence, no decryption). */
90
109
  trackPreview(track: trackType | string | number): Promise<TrackPreview | null>;
91
110
  /** Fetch a track's 30-second preview clip as a `Buffer` (plain MP3). */
@@ -18,10 +18,21 @@ class Session {
18
18
  /** The arl in use for this session. */
19
19
  arl;
20
20
  concurrency;
21
+ userId;
21
22
  constructor(arl, concurrency) {
22
23
  this.arl = arl;
23
24
  this.concurrency = concurrency;
24
25
  }
26
+ /** The logged-in user's numeric id (cached). Used by the no-arg `flow` / `favorite*` methods. */
27
+ async resolveUserId(explicit) {
28
+ if (explicit !== undefined) {
29
+ return String(explicit);
30
+ }
31
+ if (!this.userId) {
32
+ this.userId = (await (0, gerdur_core_1.getUser)()).USER_ID;
33
+ }
34
+ return this.userId;
35
+ }
25
36
  /**
26
37
  * Log in and return a ready-to-use session. Accepts either an `arl` or
27
38
  * `email`+`password` (which are exchanged for an arl via Deezer's OAuth flow).
@@ -116,6 +127,41 @@ class Session {
116
127
  albumByUPC(upc) {
117
128
  return (0, gerdur_core_1.getAlbumByUPC)(upc);
118
129
  }
130
+ // ─── Flow, radios & library (public REST) ──────────────────────────────────
131
+ // `userId` defaults to the logged-in user (via `getUser`); their profile must
132
+ // be public for these to see it.
133
+ /** Deezer **Flow** — the endless personalised mix, as tracks. */
134
+ async flow(userId, limit) {
135
+ return (0, gerdur_core_1.getUserFlow)(await this.resolveUserId(userId), limit);
136
+ }
137
+ /** A user's favourite (loved) tracks, newest first (each with `time_add`). */
138
+ async favoriteTracks(userId, limit) {
139
+ return (0, gerdur_core_1.getUserFavoriteTracks)(await this.resolveUserId(userId), limit);
140
+ }
141
+ /** A user's favourite albums. */
142
+ async favoriteAlbums(userId, limit) {
143
+ return (0, gerdur_core_1.getUserFavoriteAlbums)(await this.resolveUserId(userId), limit);
144
+ }
145
+ /** A user's favourite artists. */
146
+ async favoriteArtists(userId, limit) {
147
+ return (0, gerdur_core_1.getUserFavoriteArtists)(await this.resolveUserId(userId), limit);
148
+ }
149
+ /** A user's own + followed playlists. */
150
+ async playlists(userId, limit) {
151
+ return (0, gerdur_core_1.getUserPlaylists)(await this.resolveUserId(userId), limit);
152
+ }
153
+ /** The radios a user has favourited. */
154
+ async userRadios(userId) {
155
+ return (0, gerdur_core_1.getUserRadios)(await this.resolveUserId(userId));
156
+ }
157
+ /** Deezer's curated radio list. */
158
+ radios() {
159
+ return (0, gerdur_core_1.getRadios)();
160
+ }
161
+ /** A radio's current tracklist — a ready-to-play (public-API) source. */
162
+ radioTracks(radioId) {
163
+ return (0, gerdur_core_1.getRadioTracks)(radioId);
164
+ }
119
165
  /** The 30-second preview clip URL for a track (plain MP3 — no licence, no decryption). */
120
166
  trackPreview(track) {
121
167
  return (0, gerdur_core_1.getTrackPreview)(track);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerdur",
3
- "version": "2.5.0",
3
+ "version": "2.7.0",
4
4
  "description": "The crucial streaming module for dabox systems.",
5
5
  "author": "Christian",
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -48,7 +48,7 @@
48
48
  "adm-zip": "^0.5.16",
49
49
  "chalk": "^4.1.2",
50
50
  "commander": "^9.5.0",
51
- "gerdur-core": "^2.5.0",
51
+ "gerdur-core": "^2.9.0",
52
52
  "dot-prop": "^6.0.1",
53
53
  "got": "^11.8.6",
54
54
  "gradient-string": "^2.0.2",