gerdur-core 2.1.0 → 2.2.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,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.2.0 - 2026-08-31
4
+
5
+ Phase 2.4 — browse & discovery. All additive, all on the public REST API (no
6
+ `arl` needed), all memoised.
7
+
8
+ ### Added
9
+
10
+ - **Charts / editorial**: `getGenres`, `getChart(genreId, limit)` (the five
11
+ ranked lists), `getChartTracks`, `getGenreArtists`, `getEditorialList`,
12
+ `getEditorialReleases`, `getEditorialSelection`, `getEditorialCharts`.
13
+ - **Artist discovery**: `getArtistTopTracks`, `getRelatedArtists`,
14
+ `getArtistAlbums`, `getArtistPlaylists`, `getArtistRadioTracks`.
15
+ - **ISRC / UPC resolution**: `getTrackByISRC(isrc)` and `getAlbumByUPC(upc)` —
16
+ raw public-API track/album (with `bpm`, `gain`, `preview`, embedded `tracks`).
17
+ Complements the converter's `isrc2deezer` / `upc2deezer`, which hydrate a gw
18
+ track instead.
19
+ - New exported types: `chartType`, `chartTrack`/`chartAlbum`/`chartArtist`/
20
+ `chartPlaylist`/`chartPodcast`, `genreType`, `editorialType`,
21
+ `artistAlbumResult`, `publicApiList<T>`.
22
+
3
23
  ## 2.1.0 - 2026-08-31
4
24
 
5
25
  Phase 2.5 — search, properly. All additive.
package/README.md CHANGED
@@ -196,6 +196,41 @@ ignore the operators, so pass a plain string there.
196
196
  "as you type" UIs. `nb` (default 5) caps items per type. Needs an initialised
197
197
  session (`initDeezerApi`).
198
198
 
199
+ ### Browse & discovery
200
+
201
+ Public REST endpoints — no `arl` needed, memoised like the rest. All return a
202
+ `{data, total?, next?}` list unless noted.
203
+
204
+ | Method | Returns |
205
+ | :--- | :--- |
206
+ | `getGenres()` | Deezer's genre list (`id` `0` = "All"). |
207
+ | `getChart(genreId = 0, limit = 10)` | `{tracks, albums, artists, playlists, podcasts}` — the ranked lists for a genre. |
208
+ | `getChartTracks(genreId = 0, limit = 100, index = 0)` | just the track chart, each with a `position`. |
209
+ | `getGenreArtists(genreId)` | artists filed under a genre. |
210
+ | `getEditorialList()` | Deezer's editorial sections. |
211
+ | `getEditorialReleases(editorialId = 0, limit = 25, index = 0)` | new releases for a section. |
212
+ | `getEditorialSelection(editorialId = 0)` | albums the editors are pushing. |
213
+ | `getEditorialCharts(editorialId = 0)` | a section's charts (same 5-list shape as `getChart`). |
214
+ | `getArtistTopTracks(artistId, limit = 50)` | an artist's most popular tracks. |
215
+ | `getRelatedArtists(artistId, limit = 20)` | similar / related artists. |
216
+ | `getArtistAlbums(artistId, limit = 50, index = 0)` | the artist's discography. |
217
+ | `getArtistPlaylists(artistId, limit = 25)` | playlists featuring the artist. |
218
+ | `getArtistRadioTracks(artistId)` | a ready-made radio seeded from the artist. |
219
+ | `getTrackByISRC(isrc)` | the public-API track for an ISRC (`bpm`, `gain`, `preview`, …). |
220
+ | `getAlbumByUPC(upc)` | the public-API album (with its `tracks`) for a UPC/EAN barcode. |
221
+
222
+ ```js
223
+ const {data: genres} = await getGenres();
224
+ const rock = genres.find((g) => g.name === 'Rock');
225
+ const {tracks} = await getChart(rock.id, 20); // this week's rock chart
226
+ const similar = await getRelatedArtists(27); // artists like Daft Punk
227
+ const track = await getTrackByISRC('USUM71311296'); // "Get Lucky"
228
+ ```
229
+
230
+ `getTrackByISRC` / `getAlbumByUPC` return raw public-API objects. To download,
231
+ pass the `id` to `getTrackInfo` / `getAlbumTracks` (or use the converter's
232
+ `isrc2deezer` / `upc2deezer`, which hydrate a gw track for you).
233
+
199
234
  ### `.getTrackDownloadUrl(track, quality);`
200
235
 
201
236
  | Parameters | Required | Type | Description |
@@ -0,0 +1,49 @@
1
+ import type { albumTypePublicApi, artistAlbumResult, chartType, editorialType, genreType, publicApiList, searchResultArtist, searchResultPlaylist, searchResultTrack, trackTypePublicApi } from '../types';
2
+ /**
3
+ * The five ranked lists Deezer publishes for a genre: `tracks`, `albums`,
4
+ * `artists`, `playlists`, `podcasts`. `genreId` `0` (the default) is "all
5
+ * genres"; other ids come from {@link getGenres}.
6
+ */
7
+ export declare const getChart: (genreId?: number | string, limit?: number) => Promise<chartType>;
8
+ /** Just the track chart for a genre (`0` = all). Handy as a ready-to-play list. */
9
+ export declare const getChartTracks: (genreId?: number | string, limit?: number, index?: number) => Promise<publicApiList<searchResultTrack & {
10
+ position: number;
11
+ }>>;
12
+ /** Deezer's genre list — the `id`s feed {@link getChart}, {@link getGenreArtists}, advanced search. */
13
+ export declare const getGenres: () => Promise<publicApiList<genreType>>;
14
+ /** Artists Deezer files under a genre. */
15
+ export declare const getGenreArtists: (genreId: number | string) => Promise<publicApiList<searchResultArtist>>;
16
+ /** Deezer's editorial sections (the `id`s feed {@link getEditorialReleases} / {@link getEditorialSelection}). */
17
+ export declare const getEditorialList: () => Promise<publicApiList<editorialType>>;
18
+ /** New releases for an editorial section (`0` = the default section). */
19
+ export declare const getEditorialReleases: (editorialId?: number | string, limit?: number, index?: number) => Promise<publicApiList<artistAlbumResult>>;
20
+ /** The albums Deezer's editors are currently pushing for a section. */
21
+ export declare const getEditorialSelection: (editorialId?: number | string) => Promise<publicApiList<artistAlbumResult>>;
22
+ /** The editorial charts for a section — same five-list shape as {@link getChart}. */
23
+ export declare const getEditorialCharts: (editorialId?: number | string) => Promise<chartType>;
24
+ /** An artist's most popular tracks. */
25
+ export declare const getArtistTopTracks: (artistId: number | string, limit?: number) => Promise<publicApiList<searchResultTrack>>;
26
+ /** Artists Deezer considers related / similar. */
27
+ export declare const getRelatedArtists: (artistId: number | string, limit?: number) => Promise<publicApiList<searchResultArtist>>;
28
+ /** An artist's discography (public-API album shape). */
29
+ export declare const getArtistAlbums: (artistId: number | string, limit?: number, index?: number) => Promise<publicApiList<artistAlbumResult>>;
30
+ /** Playlists featuring an artist. */
31
+ export declare const getArtistPlaylists: (artistId: number | string, limit?: number) => Promise<publicApiList<searchResultPlaylist>>;
32
+ /** A ready-made radio (track list) seeded from an artist. */
33
+ export declare const getArtistRadioTracks: (artistId: number | string) => Promise<publicApiList<searchResultTrack>>;
34
+ /**
35
+ * Resolve an ISRC to the Deezer **public-API** track (with `bpm`, `gain`,
36
+ * `isrc`, `preview`, `contributors`). Unlike the converter's `isrc2deezer`, this
37
+ * does not hydrate a gw track — pass `result.id` to `getTrackInfo` for that.
38
+ *
39
+ * @throws when Deezer has no track for the code
40
+ */
41
+ export declare const getTrackByISRC: (isrc: string) => Promise<trackTypePublicApi>;
42
+ /**
43
+ * Resolve a UPC / EAN barcode to the Deezer **public-API** album (with its
44
+ * `tracks`). A 13-digit barcode with a leading `0` is trimmed to 12, matching
45
+ * Deezer's own lookup.
46
+ *
47
+ * @throws when Deezer has no album for the code
48
+ */
49
+ export declare const getAlbumByUPC: (upc: string) => Promise<albumTypePublicApi>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ 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.getGenres = exports.getChartTracks = exports.getChart = void 0;
4
+ const request_1 = require("./request");
5
+ const withParams = (slug, params) => {
6
+ const search = new URLSearchParams();
7
+ for (const [key, value] of Object.entries(params)) {
8
+ if (value !== undefined && value !== '') {
9
+ search.set(key, String(value));
10
+ }
11
+ }
12
+ const qs = search.toString();
13
+ return qs ? `${slug}?${qs}` : slug;
14
+ };
15
+ // ─── Charts ──────────────────────────────────────────────────────────────────
16
+ /**
17
+ * The five ranked lists Deezer publishes for a genre: `tracks`, `albums`,
18
+ * `artists`, `playlists`, `podcasts`. `genreId` `0` (the default) is "all
19
+ * genres"; other ids come from {@link getGenres}.
20
+ */
21
+ const getChart = (genreId = 0, limit = 10) => (0, request_1.requestPublicApi)(withParams(`/chart/${genreId}`, { limit }));
22
+ exports.getChart = getChart;
23
+ /** Just the track chart for a genre (`0` = all). Handy as a ready-to-play list. */
24
+ const getChartTracks = (genreId = 0, limit = 100, index = 0) => (0, request_1.requestPublicApi)(withParams(`/chart/${genreId}/tracks`, { limit, index }));
25
+ exports.getChartTracks = getChartTracks;
26
+ // ─── Genres & editorial ──────────────────────────────────────────────────────
27
+ /** Deezer's genre list — the `id`s feed {@link getChart}, {@link getGenreArtists}, advanced search. */
28
+ const getGenres = () => (0, request_1.requestPublicApi)('/genre');
29
+ exports.getGenres = getGenres;
30
+ /** Artists Deezer files under a genre. */
31
+ const getGenreArtists = (genreId) => (0, request_1.requestPublicApi)(`/genre/${genreId}/artists`);
32
+ exports.getGenreArtists = getGenreArtists;
33
+ /** Deezer's editorial sections (the `id`s feed {@link getEditorialReleases} / {@link getEditorialSelection}). */
34
+ const getEditorialList = () => (0, request_1.requestPublicApi)('/editorial');
35
+ exports.getEditorialList = getEditorialList;
36
+ /** New releases for an editorial section (`0` = the default section). */
37
+ const getEditorialReleases = (editorialId = 0, limit = 25, index = 0) => (0, request_1.requestPublicApi)(withParams(`/editorial/${editorialId}/releases`, { limit, index }));
38
+ exports.getEditorialReleases = getEditorialReleases;
39
+ /** The albums Deezer's editors are currently pushing for a section. */
40
+ const getEditorialSelection = (editorialId = 0) => (0, request_1.requestPublicApi)(`/editorial/${editorialId}/selection`);
41
+ exports.getEditorialSelection = getEditorialSelection;
42
+ /** The editorial charts for a section — same five-list shape as {@link getChart}. */
43
+ const getEditorialCharts = (editorialId = 0) => (0, request_1.requestPublicApi)(`/editorial/${editorialId}/charts`);
44
+ exports.getEditorialCharts = getEditorialCharts;
45
+ // ─── Artist discovery ────────────────────────────────────────────────────────
46
+ /** An artist's most popular tracks. */
47
+ const getArtistTopTracks = (artistId, limit = 50) => (0, request_1.requestPublicApi)(withParams(`/artist/${artistId}/top`, { limit }));
48
+ exports.getArtistTopTracks = getArtistTopTracks;
49
+ /** Artists Deezer considers related / similar. */
50
+ const getRelatedArtists = (artistId, limit = 20) => (0, request_1.requestPublicApi)(withParams(`/artist/${artistId}/related`, { limit }));
51
+ exports.getRelatedArtists = getRelatedArtists;
52
+ /** An artist's discography (public-API album shape). */
53
+ const getArtistAlbums = (artistId, limit = 50, index = 0) => (0, request_1.requestPublicApi)(withParams(`/artist/${artistId}/albums`, { limit, index }));
54
+ exports.getArtistAlbums = getArtistAlbums;
55
+ /** Playlists featuring an artist. */
56
+ const getArtistPlaylists = (artistId, limit = 25) => (0, request_1.requestPublicApi)(withParams(`/artist/${artistId}/playlists`, { limit }));
57
+ exports.getArtistPlaylists = getArtistPlaylists;
58
+ /** A ready-made radio (track list) seeded from an artist. */
59
+ const getArtistRadioTracks = (artistId) => (0, request_1.requestPublicApi)(`/artist/${artistId}/radio`);
60
+ exports.getArtistRadioTracks = getArtistRadioTracks;
61
+ // ─── ISRC / UPC resolution ───────────────────────────────────────────────────
62
+ /**
63
+ * Resolve an ISRC to the Deezer **public-API** track (with `bpm`, `gain`,
64
+ * `isrc`, `preview`, `contributors`). Unlike the converter's `isrc2deezer`, this
65
+ * does not hydrate a gw track — pass `result.id` to `getTrackInfo` for that.
66
+ *
67
+ * @throws when Deezer has no track for the code
68
+ */
69
+ const getTrackByISRC = (isrc) => (0, request_1.requestPublicApi)(`/track/isrc:${encodeURIComponent(isrc)}`);
70
+ exports.getTrackByISRC = getTrackByISRC;
71
+ /**
72
+ * Resolve a UPC / EAN barcode to the Deezer **public-API** album (with its
73
+ * `tracks`). A 13-digit barcode with a leading `0` is trimmed to 12, matching
74
+ * Deezer's own lookup.
75
+ *
76
+ * @throws when Deezer has no album for the code
77
+ */
78
+ const getAlbumByUPC = (upc) => {
79
+ const code = upc.length > 12 && upc.startsWith('0') ? upc.slice(-12) : upc;
80
+ return (0, request_1.requestPublicApi)(`/album/upc:${encodeURIComponent(code)}`);
81
+ };
82
+ exports.getAlbumByUPC = getAlbumByUPC;
@@ -1,3 +1,4 @@
1
1
  export * from './api';
2
2
  export * from './request';
3
3
  export * from './search';
4
+ export * from './browse';
package/dist/api/index.js CHANGED
@@ -17,3 +17,4 @@ Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./api"), exports);
18
18
  __exportStar(require("./request"), exports);
19
19
  __exportStar(require("./search"), exports);
20
+ __exportStar(require("./browse"), exports);
@@ -0,0 +1,85 @@
1
+ import type { searchResultAlbum, searchResultArtist, searchResultPlaylist, searchResultTrack } from './search';
2
+ /** The `{data, total, next?, prev?}` envelope every paginated public-API list uses. */
3
+ export interface publicApiList<T> {
4
+ data: T[];
5
+ total?: number;
6
+ /** absolute URL of the next page, when there is one */
7
+ next?: string;
8
+ prev?: string;
9
+ }
10
+ export interface chartTrack extends searchResultTrack {
11
+ /** 1-based position in the chart */
12
+ position: number;
13
+ }
14
+ export interface chartArtist extends searchResultArtist {
15
+ position: number;
16
+ }
17
+ export interface chartAlbum extends searchResultAlbum {
18
+ position: number;
19
+ }
20
+ export interface chartPlaylist extends searchResultPlaylist {
21
+ position: number;
22
+ }
23
+ export interface chartPodcast {
24
+ id: number;
25
+ title: string;
26
+ description?: string;
27
+ available?: boolean;
28
+ fans?: number;
29
+ link?: string;
30
+ share?: string;
31
+ picture: string;
32
+ picture_small?: string;
33
+ picture_medium?: string;
34
+ picture_big?: string;
35
+ picture_xl?: string;
36
+ position: number;
37
+ type: 'podcast';
38
+ }
39
+ /** `/chart/{genreId}` — the five ranked lists Deezer publishes per genre (`0` = all genres). */
40
+ export interface chartType {
41
+ tracks: publicApiList<chartTrack>;
42
+ albums: publicApiList<chartAlbum>;
43
+ artists: publicApiList<chartArtist>;
44
+ playlists: publicApiList<chartPlaylist>;
45
+ podcasts: publicApiList<chartPodcast>;
46
+ }
47
+ export interface genreType {
48
+ id: number;
49
+ name: string;
50
+ picture: string;
51
+ picture_small?: string;
52
+ picture_medium?: string;
53
+ picture_big?: string;
54
+ picture_xl?: string;
55
+ type: 'genre';
56
+ }
57
+ export interface editorialType {
58
+ id: number;
59
+ name: string;
60
+ picture: string;
61
+ picture_small?: string;
62
+ picture_medium?: string;
63
+ picture_big?: string;
64
+ picture_xl?: string;
65
+ type: 'editorial';
66
+ }
67
+ /** An album from `/artist/{id}/albums` — the artist's own discography, public-API shape. */
68
+ export interface artistAlbumResult {
69
+ id: number;
70
+ title: string;
71
+ link: string;
72
+ cover: string;
73
+ cover_small?: string;
74
+ cover_medium?: string;
75
+ cover_big?: string;
76
+ cover_xl?: string;
77
+ md5_image: string;
78
+ genre_id: number;
79
+ fans?: number;
80
+ release_date: string;
81
+ record_type: string;
82
+ tracklist: string;
83
+ explicit_lyrics: boolean;
84
+ type: 'album';
85
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,5 +1,6 @@
1
1
  export * from './album';
2
2
  export * from './artist';
3
+ export * from './browse';
3
4
  export * from './show';
4
5
  export * from './playlist';
5
6
  export * from './playlist-channel';
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./album"), exports);
18
18
  __exportStar(require("./artist"), exports);
19
+ __exportStar(require("./browse"), exports);
19
20
  __exportStar(require("./show"), exports);
20
21
  __exportStar(require("./playlist"), exports);
21
22
  __exportStar(require("./playlist-channel"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerdur-core",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Core module for gerdur.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",