gerdur 2.5.0 → 2.6.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,20 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.6.0 - 2026-08-31
4
+
5
+ ### Added
6
+
7
+ - **`gerdur-core@^2.6.0`** — re-exports the Flow / radios / library surface:
8
+ `getUserFlow`, `getUserFavoriteTracks` / `Albums` / `Artists`,
9
+ `getUserPlaylists`, `getUserRadios`, `getUserChartTracks`, `getRadios`,
10
+ `getRadioTracks`, `getRadioGenres` + their types.
11
+ - **`Session` methods**: `flow`, `favoriteTracks`, `favoriteAlbums`,
12
+ `favoriteArtists`, `playlists`, `userRadios`, `radios`, `radioTracks` — the
13
+ `userId` argument defaults to the logged-in user.
14
+ - **CLI `flow` / `flow:<userId>` / `radio:<id>`** — pick tracks from your (or
15
+ another user's) Flow, or a radio's current playlist, and download them.
16
+ Headless-friendly.
17
+
3
18
  ## 2.5.0 - 2026-08-31
4
19
 
5
20
  ### Changed
package/README.md CHANGED
@@ -159,8 +159,11 @@ 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 |
162
165
 
163
- `isrc:` and `upc:` also work in `--headless` mode (`-u isrc:…` / `-u upc:…`).
166
+ `isrc:` / `upc:` / `flow` / `radio:` also work in `--headless` mode (`-u flow`, ).
164
167
 
165
168
  ### From flags (works headless)
166
169
 
@@ -258,6 +261,9 @@ Session methods:
258
261
  - **browse** — `genres`, `chart`, `chartTracks`, `editorialSections`,
259
262
  `artistTopTracks`, `relatedArtists`, `artistAlbums`, `artistRadio`,
260
263
  `trackByISRC`, `albumByUPC`
264
+ - **flow / library** — `flow`, `favoriteTracks`, `favoriteAlbums`,
265
+ `favoriteArtists`, `playlists`, `userRadios`, `radios`, `radioTracks`
266
+ (the `userId` arg defaults to the logged-in user)
261
267
  - **user / download** — `getUser`, `getTrackBuffer`, `streamTrack`,
262
268
  `downloadTrack`, `downloadTracks`, `downloadUrl`, `trackPreview`, `downloadPreview`
263
269
 
@@ -319,6 +325,10 @@ or `createSession`):
319
325
  `getEditorialCharts`, `getArtistTopTracks`, `getRelatedArtists`,
320
326
  `getArtistAlbums`, `getArtistPlaylists`, `getArtistRadioTracks`,
321
327
  `getTrackByISRC`, `getAlbumByUPC`
328
+ - **Flow / library** — `getUserFlow`, `getUserFavoriteTracks`,
329
+ `getUserFavoriteAlbums`, `getUserFavoriteArtists`, `getUserPlaylists`,
330
+ `getUserRadios`, `getUserChartTracks`, `getRadios`, `getRadioTracks`,
331
+ `getRadioGenres`
322
332
  - **Download** — `getTrackDownloadUrl`, `resolveDownloadUrls`,
323
333
  `streamTrackDownload`, `createDecryptStream`, `getStream`, `getTrackPreview`,
324
334
  `downloadPreview`, `formatName`, `toFormat`, `DEEZER_FORMATS`
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerdur",
3
- "version": "2.5.0",
3
+ "version": "2.6.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.6.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>`:',
232
240
  validate: (value) => (value ? true : false),
233
241
  },
234
242
  ], { onCancel });
@@ -260,6 +268,26 @@ 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
+ }
263
291
  if (!searchData && !url.match(urlRegex)) {
264
292
  if (options.headless) {
265
293
  throw new Error('Please provide a valid URL. Unknown URL: ' + url);
@@ -59,7 +59,7 @@ export type { SessionOptions, DownloadTracksOptions, SearchType } from './lib/se
59
59
  export { getTrackBuffer, getTaggedTrack, downloadTrackToFile } from './lib/api-download';
60
60
  export type { Quality, GetTrackBufferOptions, DownloadTrackOptions, DownloadResult } from './lib/api-download';
61
61
  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';
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, 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, createDecryptStream, getStream, addTrackTags, getRichAlbum, normalizeContributors, toLrc, GeoBlocked, DeezerError, } from 'gerdur-core';
63
63
  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';
64
+ 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
65
  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.toFormat = exports.formatName = exports.downloadPreview = 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.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 = exports.getLyrics = exports.getDiscography = exports.getArtistInfo = exports.getPlaylistTracks = exports.getPlaylistInfo = exports.getAlbumTracks = exports.getAlbumInfo = exports.getTrackInfo = exports.getUser = exports.DEEZER_FORMATS = 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; } });
@@ -110,6 +110,16 @@ Object.defineProperty(exports, "getRelatedArtists", { enumerable: true, get: fun
110
110
  Object.defineProperty(exports, "getArtistAlbums", { enumerable: true, get: function () { return gerdur_core_1.getArtistAlbums; } });
111
111
  Object.defineProperty(exports, "getArtistPlaylists", { enumerable: true, get: function () { return gerdur_core_1.getArtistPlaylists; } });
112
112
  Object.defineProperty(exports, "getArtistRadioTracks", { enumerable: true, get: function () { return gerdur_core_1.getArtistRadioTracks; } });
113
+ Object.defineProperty(exports, "getUserFlow", { enumerable: true, get: function () { return gerdur_core_1.getUserFlow; } });
114
+ Object.defineProperty(exports, "getUserFavoriteTracks", { enumerable: true, get: function () { return gerdur_core_1.getUserFavoriteTracks; } });
115
+ Object.defineProperty(exports, "getUserFavoriteAlbums", { enumerable: true, get: function () { return gerdur_core_1.getUserFavoriteAlbums; } });
116
+ Object.defineProperty(exports, "getUserFavoriteArtists", { enumerable: true, get: function () { return gerdur_core_1.getUserFavoriteArtists; } });
117
+ Object.defineProperty(exports, "getUserPlaylists", { enumerable: true, get: function () { return gerdur_core_1.getUserPlaylists; } });
118
+ Object.defineProperty(exports, "getUserRadios", { enumerable: true, get: function () { return gerdur_core_1.getUserRadios; } });
119
+ Object.defineProperty(exports, "getUserChartTracks", { enumerable: true, get: function () { return gerdur_core_1.getUserChartTracks; } });
120
+ Object.defineProperty(exports, "getRadios", { enumerable: true, get: function () { return gerdur_core_1.getRadios; } });
121
+ Object.defineProperty(exports, "getRadioTracks", { enumerable: true, get: function () { return gerdur_core_1.getRadioTracks; } });
122
+ Object.defineProperty(exports, "getRadioGenres", { enumerable: true, get: function () { return gerdur_core_1.getRadioGenres; } });
113
123
  Object.defineProperty(exports, "getTrackByISRC", { enumerable: true, get: function () { return gerdur_core_1.getTrackByISRC; } });
114
124
  Object.defineProperty(exports, "getAlbumByUPC", { enumerable: true, get: function () { return gerdur_core_1.getAlbumByUPC; } });
115
125
  Object.defineProperty(exports, "getTrackPreview", { enumerable: true, get: function () { return gerdur_core_1.getTrackPreview; } });
@@ -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.6.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.6.0",
52
52
  "dot-prop": "^6.0.1",
53
53
  "got": "^11.8.6",
54
54
  "gradient-string": "^2.0.2",