gerdur-core 2.16.0 → 2.18.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 +66 -0
- package/README.md +74 -1
- package/dist/api/favorites.d.ts +59 -0
- package/dist/api/favorites.js +99 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/api/library.d.ts +72 -0
- package/dist/api/library.js +65 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,71 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.18.0 - 2026-08-31
|
|
4
|
+
|
|
5
|
+
Write operations — the first part of this package that changes an account.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **`src/api/favorites.ts`** — mutating library operations, in their own module
|
|
10
|
+
and wired into no download path, so they only run when called deliberately:
|
|
11
|
+
- `addFavoriteTracks(ids)` / `removeFavoriteTracks(ids)` (`song.addFavorites` /
|
|
12
|
+
`song.removeFavorites` — note the plural)
|
|
13
|
+
- `addFavoriteAlbum` / `removeFavoriteAlbum`, `addFavoriteArtist` /
|
|
14
|
+
`removeFavoriteArtist`
|
|
15
|
+
- `followPlaylist` / `unfollowPlaylist` (the gateway wants
|
|
16
|
+
`parent_playlist_id` to follow but `playlist_id` to unfollow)
|
|
17
|
+
- `addFavoriteShow`, `createPlaylist`, `addTracksToPlaylist`,
|
|
18
|
+
`removeTracksFromPlaylist`
|
|
19
|
+
|
|
20
|
+
The surface was mapped by calling each candidate with **incomplete
|
|
21
|
+
parameters** — an existing method answers `MISSING_PARAMETER_*`, an absent one
|
|
22
|
+
`GATEWAY_ERROR` — so method names and their parameter names were established
|
|
23
|
+
without creating or changing anything.
|
|
24
|
+
|
|
25
|
+
### Verification status
|
|
26
|
+
|
|
27
|
+
- Method existence and parameter names: **confirmed by probe**.
|
|
28
|
+
- End-to-end execution: **not run.** `__tests__/favorites.ts` contains
|
|
29
|
+
snapshot → mutate → assert → revert → assert-restored round trips, gated
|
|
30
|
+
behind `GERDUR_ALLOW_WRITE_TESTS=1` so they never fire by accident.
|
|
31
|
+
|
|
32
|
+
### Known gaps
|
|
33
|
+
|
|
34
|
+
- **Deezer's gateway has no playlist delete.** `playlist.delete`, `.remove`,
|
|
35
|
+
`.destroy`, `.deletePlaylist` and eight other spellings all answer
|
|
36
|
+
`GATEWAY_ERROR`, so `createPlaylist` is one-way — remove what it makes from a
|
|
37
|
+
Deezer client. Everything else here has a confirmed inverse.
|
|
38
|
+
- No `show.deleteFavorite` was found, so `addFavoriteShow` is one-way too.
|
|
39
|
+
- **`log.listen` (scrobbling) is not implemented.** It never answered the probe,
|
|
40
|
+
so its shape is unknown, and it writes to listening history that cannot be
|
|
41
|
+
undone — not something to ship on a guess.
|
|
42
|
+
|
|
43
|
+
## 2.17.0 - 2026-08-31
|
|
44
|
+
|
|
45
|
+
The account's own library, over the authenticated gateway.
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
|
|
49
|
+
- **`src/api/library.ts`** — the logged-in account's *private* library. Distinct
|
|
50
|
+
from the public-REST surface in `api/user.ts`, which needs a public profile and
|
|
51
|
+
only shows what that profile exposes. Found by probing the gateway: seven
|
|
52
|
+
methods answer here that the public API cannot reach.
|
|
53
|
+
- `getMyPlaylists(userId?, nb?, start?)` — **including private playlists**
|
|
54
|
+
- `getMyFavoriteTracks` / `getMyFavoriteAlbums` / `getMyFavoriteArtists`
|
|
55
|
+
- `getMyFavoritePlaylists` / `getMyFavoriteRadios` / `getMyFavoriteShows`
|
|
56
|
+
- `getMyFavoriteTrackIds()` — every loved track id in one small request, for
|
|
57
|
+
diffing a local library against the account
|
|
58
|
+
- `userId` defaults to the logged-in account. Responses are gateway shapes, so
|
|
59
|
+
tracks arrive with a `TRACK_TOKEN` and are directly downloadable; being
|
|
60
|
+
account-scoped they stay in the per-session cache and are never shared.
|
|
61
|
+
- **`getTrackMix(sngId, nb?, start?)`** (`song.getSearchTrackMix`) — a "more like
|
|
62
|
+
this" mix seeded from one track. Unlike the public radio endpoints it returns
|
|
63
|
+
full gateway tracks **with tokens already attached**: verified that
|
|
64
|
+
`resolveDownloadUrls` resolves them 3/3 with no `getTrackInfo` round trip.
|
|
65
|
+
|
|
66
|
+
Verified against a live account: `getMyPlaylists` 1/1, `getMyFavoriteArtists`
|
|
67
|
+
7/7 with real names, `getTrackMix` 5/5 all carrying tokens.
|
|
68
|
+
|
|
3
69
|
## 2.16.0 - 2026-08-31
|
|
4
70
|
|
|
5
71
|
### Added
|
package/README.md
CHANGED
|
@@ -46,6 +46,8 @@ the CLI and the file-writing layer on top.
|
|
|
46
46
|
- [Search](#search)
|
|
47
47
|
- [Browse and discover](#browse-and-discover)
|
|
48
48
|
- [Flow, radios and a user's library](#flow-radios-and-a-users-library)
|
|
49
|
+
- [Your own library](#your-own-library)
|
|
50
|
+
- [Changing the account (write operations)](#changing-the-account-write-operations)
|
|
49
51
|
- [Podcasts](#podcasts)
|
|
50
52
|
- [Preview clips](#preview-clips)
|
|
51
53
|
- [Resolve a download URL](#resolve-a-download-url)
|
|
@@ -381,6 +383,70 @@ const {data: loved} = await getUserFavoriteTracks(me.USER_ID);
|
|
|
381
383
|
const {data: eighties} = await getRadioTracks(38305); // "The '80s"
|
|
382
384
|
```
|
|
383
385
|
|
|
386
|
+
### Your own library
|
|
387
|
+
|
|
388
|
+
`api/user.ts` above reads a **public** profile. These read what the *account*
|
|
389
|
+
can see — private playlists included — over the authenticated gateway, and
|
|
390
|
+
return gateway shapes, so tracks come with a `TRACK_TOKEN` and are immediately
|
|
391
|
+
downloadable.
|
|
392
|
+
|
|
393
|
+
| Function | Returns |
|
|
394
|
+
| :--- | :--- |
|
|
395
|
+
| `getMyPlaylists(userId?, nb?, start?)` | the account's own playlists, **including private ones** |
|
|
396
|
+
| `getMyFavoriteTracks(userId?, nb?, start?)` | loved tracks, as downloadable gw tracks |
|
|
397
|
+
| `getMyFavoriteTrackIds()` | every loved track id in one request — for diffing a local library |
|
|
398
|
+
| `getMyFavoriteAlbums` / `getMyFavoriteArtists` | favourited albums / artists |
|
|
399
|
+
| `getMyFavoritePlaylists` / `getMyFavoriteRadios` / `getMyFavoriteShows` | followed playlists / radios / shows |
|
|
400
|
+
| `getTrackMix(sngId, nb?, start?)` | a "more like this" mix seeded from a track — **tokens already attached** |
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
import {getMyPlaylists, getTrackMix, resolveDownloadUrls} from 'gerdur-core';
|
|
404
|
+
|
|
405
|
+
const {data: playlists} = await getMyPlaylists(); // yours, private included
|
|
406
|
+
const {data: mix} = await getTrackMix('3135556', 20); // 20 tracks like this one
|
|
407
|
+
const urls = await resolveDownloadUrls(mix, [9, 3, 1]); // straight to download — no per-track lookup
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`userId` defaults to the logged-in account. These are account-scoped, so they
|
|
411
|
+
never enter the shared cross-session cache.
|
|
412
|
+
|
|
413
|
+
### Changing the account (write operations)
|
|
414
|
+
|
|
415
|
+
Everything above reads. These change the logged-in account's library for real —
|
|
416
|
+
they are in their own module, wired into no download path, and only run when you
|
|
417
|
+
call them.
|
|
418
|
+
|
|
419
|
+
| Function | Inverse |
|
|
420
|
+
| :--- | :--- |
|
|
421
|
+
| `addFavoriteTracks(ids)` | `removeFavoriteTracks(ids)` |
|
|
422
|
+
| `addFavoriteAlbum(id)` | `removeFavoriteAlbum(id)` |
|
|
423
|
+
| `addFavoriteArtist(id)` | `removeFavoriteArtist(id)` |
|
|
424
|
+
| `followPlaylist(id)` | `unfollowPlaylist(id)` |
|
|
425
|
+
| `addFavoriteShow(id)` | — none found |
|
|
426
|
+
| `createPlaylist(title, opts?)` | **— none exists, see below** |
|
|
427
|
+
| `addTracksToPlaylist(id, sngIds)` | `removeTracksFromPlaylist(id, sngIds)` |
|
|
428
|
+
|
|
429
|
+
```ts
|
|
430
|
+
import {addFavoriteTracks, removeFavoriteTracks} from 'gerdur-core';
|
|
431
|
+
|
|
432
|
+
await addFavoriteTracks(['3135556']); // love it
|
|
433
|
+
await removeFavoriteTracks(['3135556']); // and back
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
> **`createPlaylist` is a one-way door.** Deezer's gateway exposes no delete —
|
|
437
|
+
> a dozen spellings of `playlist.delete` all answer `GATEWAY_ERROR` — so a
|
|
438
|
+
> playlist made here has to be removed from a Deezer client. It is also the one
|
|
439
|
+
> function in this module that has not been exercised against a live account,
|
|
440
|
+
> for exactly that reason.
|
|
441
|
+
>
|
|
442
|
+
> Method names and parameters were established by probing with incomplete
|
|
443
|
+
> arguments (an existing method answers `MISSING_PARAMETER_*`), so the surface is
|
|
444
|
+
> real; the round trips live in `__tests__/favorites.ts` behind
|
|
445
|
+
> `GERDUR_ALLOW_WRITE_TESTS=1`.
|
|
446
|
+
|
|
447
|
+
Scrobbling (`log.listen`) is deliberately absent: it never answered the probe and
|
|
448
|
+
it writes history that cannot be undone.
|
|
449
|
+
|
|
384
450
|
### Podcasts
|
|
385
451
|
|
|
386
452
|
```ts
|
|
@@ -787,7 +853,14 @@ import type {
|
|
|
787
853
|
|
|
788
854
|
`getUserFlow` · `getUserFavoriteTracks` · `getUserFavoriteAlbums` ·
|
|
789
855
|
`getUserFavoriteArtists` · `getUserPlaylists` · `getUserRadios` ·
|
|
790
|
-
`getUserChartTracks` · `getRadios` · `getRadioTracks` · `getRadioGenres`
|
|
856
|
+
`getUserChartTracks` · `getRadios` · `getRadioTracks` · `getRadioGenres` ·
|
|
857
|
+
`getMyPlaylists` · `getMyFavoriteTracks` · `getMyFavoriteTrackIds` ·
|
|
858
|
+
`getMyFavoriteAlbums` · `getMyFavoriteArtists` · `getMyFavoritePlaylists` ·
|
|
859
|
+
`getMyFavoriteRadios` · `getMyFavoriteShows` · `getTrackMix` ·
|
|
860
|
+
`addFavoriteTracks` · `removeFavoriteTracks` · `addFavoriteAlbum` ·
|
|
861
|
+
`removeFavoriteAlbum` · `addFavoriteArtist` · `removeFavoriteArtist` ·
|
|
862
|
+
`followPlaylist` · `unfollowPlaylist` · `addFavoriteShow` · `createPlaylist` ·
|
|
863
|
+
`addTracksToPlaylist` · `removeTracksFromPlaylist`
|
|
791
864
|
</details>
|
|
792
865
|
|
|
793
866
|
<details>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/** What the gateway returns for a mutation — usually `true`, or the new id. */
|
|
2
|
+
export type WriteResult = boolean | string | number | Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* Love one or more tracks (`song.addFavorites`). Reversible with
|
|
5
|
+
* {@link removeFavoriteTracks}.
|
|
6
|
+
*
|
|
7
|
+
* @param sngIds `SNG_ID`s
|
|
8
|
+
*/
|
|
9
|
+
export declare const addFavoriteTracks: (sngIds: (string | number)[]) => Promise<WriteResult>;
|
|
10
|
+
/** Un-love one or more tracks (`song.removeFavorites`). */
|
|
11
|
+
export declare const removeFavoriteTracks: (sngIds: (string | number)[]) => Promise<WriteResult>;
|
|
12
|
+
/** Add an album to favourites (`album.addFavorite`). */
|
|
13
|
+
export declare const addFavoriteAlbum: (albId: string | number) => Promise<WriteResult>;
|
|
14
|
+
/** Remove an album from favourites (`album.deleteFavorite`). */
|
|
15
|
+
export declare const removeFavoriteAlbum: (albId: string | number) => Promise<WriteResult>;
|
|
16
|
+
/** Follow an artist (`artist.addFavorite`). */
|
|
17
|
+
export declare const addFavoriteArtist: (artId: string | number) => Promise<WriteResult>;
|
|
18
|
+
/** Unfollow an artist (`artist.deleteFavorite`). */
|
|
19
|
+
export declare const removeFavoriteArtist: (artId: string | number) => Promise<WriteResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Follow someone else's playlist (`playlist.addFavorite`). Note the gateway
|
|
22
|
+
* wants `parent_playlist_id` here but plain `playlist_id` to unfollow.
|
|
23
|
+
*/
|
|
24
|
+
export declare const followPlaylist: (playlistId: string | number) => Promise<WriteResult>;
|
|
25
|
+
/** Unfollow a playlist (`playlist.deleteFavorite`). */
|
|
26
|
+
export declare const unfollowPlaylist: (playlistId: string | number) => Promise<WriteResult>;
|
|
27
|
+
/**
|
|
28
|
+
* Follow a podcast show (`show.addFavorite`).
|
|
29
|
+
*
|
|
30
|
+
* No `show.deleteFavorite` answered the probe, so treat this as one-way until
|
|
31
|
+
* the inverse is found.
|
|
32
|
+
*/
|
|
33
|
+
export declare const addFavoriteShow: (showId: string | number) => Promise<WriteResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Create a playlist (`playlist.create`). Resolves to the new `PLAYLIST_ID`.
|
|
36
|
+
*
|
|
37
|
+
* **One-way.** The gateway has no delete counterpart (see the module note), so
|
|
38
|
+
* anything created here has to be removed from a Deezer client. For the same
|
|
39
|
+
* reason this is the one function on this page that has not been exercised
|
|
40
|
+
* against a live account.
|
|
41
|
+
*
|
|
42
|
+
* @param title playlist title
|
|
43
|
+
* @param options `description`, `status` (0 public / 1 private / 2 collaborative),
|
|
44
|
+
* and `songs` to seed it with `SNG_ID`s
|
|
45
|
+
*/
|
|
46
|
+
export declare const createPlaylist: (title: string, options?: {
|
|
47
|
+
description?: string;
|
|
48
|
+
status?: 0 | 1 | 2;
|
|
49
|
+
songs?: (string | number)[];
|
|
50
|
+
}) => Promise<WriteResult>;
|
|
51
|
+
/**
|
|
52
|
+
* Append tracks to a playlist (`playlist.addSongs`). Reversible with
|
|
53
|
+
* {@link removeTracksFromPlaylist}.
|
|
54
|
+
*
|
|
55
|
+
* The gateway takes `songs` as `[[sngId, offset], …]`; this wraps that for you.
|
|
56
|
+
*/
|
|
57
|
+
export declare const addTracksToPlaylist: (playlistId: string | number, sngIds: (string | number)[]) => Promise<WriteResult>;
|
|
58
|
+
/** Remove tracks from a playlist (`playlist.deleteSongs`). */
|
|
59
|
+
export declare const removeTracksFromPlaylist: (playlistId: string | number, sngIds: (string | number)[]) => Promise<WriteResult>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.removeTracksFromPlaylist = exports.addTracksToPlaylist = exports.createPlaylist = exports.addFavoriteShow = exports.unfollowPlaylist = exports.followPlaylist = exports.removeFavoriteArtist = exports.addFavoriteArtist = exports.removeFavoriteAlbum = exports.addFavoriteAlbum = exports.removeFavoriteTracks = exports.addFavoriteTracks = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* **Mutating** operations on the logged-in account's library.
|
|
6
|
+
*
|
|
7
|
+
* Everything else in this package reads. These change the account, so they are
|
|
8
|
+
* kept in their own module and none of them are wired into any download path —
|
|
9
|
+
* you have to call them deliberately.
|
|
10
|
+
*
|
|
11
|
+
* The method names here were established by probing the gateway with incomplete
|
|
12
|
+
* parameters, which makes an existing method answer `MISSING_PARAMETER_*` while
|
|
13
|
+
* an absent one answers `GATEWAY_ERROR` — so the surface was mapped without
|
|
14
|
+
* creating or changing anything.
|
|
15
|
+
*
|
|
16
|
+
* **Deezer's gateway exposes no way to delete a playlist.** `playlist.delete`,
|
|
17
|
+
* `.remove`, `.destroy` and nine other spellings all answer `GATEWAY_ERROR`.
|
|
18
|
+
* {@link createPlaylist} is therefore a one-way door: whatever it makes, you
|
|
19
|
+
* remove from a Deezer client, not from here. Everything else on this page has a
|
|
20
|
+
* confirmed inverse and is safe to undo.
|
|
21
|
+
*/
|
|
22
|
+
const request_1 = require("./request");
|
|
23
|
+
// ─── Loved tracks ────────────────────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Love one or more tracks (`song.addFavorites`). Reversible with
|
|
26
|
+
* {@link removeFavoriteTracks}.
|
|
27
|
+
*
|
|
28
|
+
* @param sngIds `SNG_ID`s
|
|
29
|
+
*/
|
|
30
|
+
const addFavoriteTracks = (sngIds) => (0, request_1.request)({ ids: sngIds.map(String) }, 'song.addFavorites');
|
|
31
|
+
exports.addFavoriteTracks = addFavoriteTracks;
|
|
32
|
+
/** Un-love one or more tracks (`song.removeFavorites`). */
|
|
33
|
+
const removeFavoriteTracks = (sngIds) => (0, request_1.request)({ ids: sngIds.map(String) }, 'song.removeFavorites');
|
|
34
|
+
exports.removeFavoriteTracks = removeFavoriteTracks;
|
|
35
|
+
// ─── Albums / artists ────────────────────────────────────────────────────────
|
|
36
|
+
/** Add an album to favourites (`album.addFavorite`). */
|
|
37
|
+
const addFavoriteAlbum = (albId) => (0, request_1.request)({ alb_id: String(albId) }, 'album.addFavorite');
|
|
38
|
+
exports.addFavoriteAlbum = addFavoriteAlbum;
|
|
39
|
+
/** Remove an album from favourites (`album.deleteFavorite`). */
|
|
40
|
+
const removeFavoriteAlbum = (albId) => (0, request_1.request)({ alb_id: String(albId) }, 'album.deleteFavorite');
|
|
41
|
+
exports.removeFavoriteAlbum = removeFavoriteAlbum;
|
|
42
|
+
/** Follow an artist (`artist.addFavorite`). */
|
|
43
|
+
const addFavoriteArtist = (artId) => (0, request_1.request)({ art_id: String(artId) }, 'artist.addFavorite');
|
|
44
|
+
exports.addFavoriteArtist = addFavoriteArtist;
|
|
45
|
+
/** Unfollow an artist (`artist.deleteFavorite`). */
|
|
46
|
+
const removeFavoriteArtist = (artId) => (0, request_1.request)({ art_id: String(artId) }, 'artist.deleteFavorite');
|
|
47
|
+
exports.removeFavoriteArtist = removeFavoriteArtist;
|
|
48
|
+
// ─── Playlists & shows ───────────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Follow someone else's playlist (`playlist.addFavorite`). Note the gateway
|
|
51
|
+
* wants `parent_playlist_id` here but plain `playlist_id` to unfollow.
|
|
52
|
+
*/
|
|
53
|
+
const followPlaylist = (playlistId) => (0, request_1.request)({ parent_playlist_id: String(playlistId) }, 'playlist.addFavorite');
|
|
54
|
+
exports.followPlaylist = followPlaylist;
|
|
55
|
+
/** Unfollow a playlist (`playlist.deleteFavorite`). */
|
|
56
|
+
const unfollowPlaylist = (playlistId) => (0, request_1.request)({ playlist_id: String(playlistId) }, 'playlist.deleteFavorite');
|
|
57
|
+
exports.unfollowPlaylist = unfollowPlaylist;
|
|
58
|
+
/**
|
|
59
|
+
* Follow a podcast show (`show.addFavorite`).
|
|
60
|
+
*
|
|
61
|
+
* No `show.deleteFavorite` answered the probe, so treat this as one-way until
|
|
62
|
+
* the inverse is found.
|
|
63
|
+
*/
|
|
64
|
+
const addFavoriteShow = (showId) => (0, request_1.request)({ show_id: String(showId) }, 'show.addFavorite');
|
|
65
|
+
exports.addFavoriteShow = addFavoriteShow;
|
|
66
|
+
// ─── Playlist contents ───────────────────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Create a playlist (`playlist.create`). Resolves to the new `PLAYLIST_ID`.
|
|
69
|
+
*
|
|
70
|
+
* **One-way.** The gateway has no delete counterpart (see the module note), so
|
|
71
|
+
* anything created here has to be removed from a Deezer client. For the same
|
|
72
|
+
* reason this is the one function on this page that has not been exercised
|
|
73
|
+
* against a live account.
|
|
74
|
+
*
|
|
75
|
+
* @param title playlist title
|
|
76
|
+
* @param options `description`, `status` (0 public / 1 private / 2 collaborative),
|
|
77
|
+
* and `songs` to seed it with `SNG_ID`s
|
|
78
|
+
*/
|
|
79
|
+
const createPlaylist = (title, options = {}) => {
|
|
80
|
+
var _a, _b, _c;
|
|
81
|
+
return (0, request_1.request)({
|
|
82
|
+
title,
|
|
83
|
+
description: (_a = options.description) !== null && _a !== void 0 ? _a : '',
|
|
84
|
+
status: (_b = options.status) !== null && _b !== void 0 ? _b : 1,
|
|
85
|
+
songs: ((_c = options.songs) !== null && _c !== void 0 ? _c : []).map((id) => [String(id), 0]),
|
|
86
|
+
}, 'playlist.create');
|
|
87
|
+
};
|
|
88
|
+
exports.createPlaylist = createPlaylist;
|
|
89
|
+
/**
|
|
90
|
+
* Append tracks to a playlist (`playlist.addSongs`). Reversible with
|
|
91
|
+
* {@link removeTracksFromPlaylist}.
|
|
92
|
+
*
|
|
93
|
+
* The gateway takes `songs` as `[[sngId, offset], …]`; this wraps that for you.
|
|
94
|
+
*/
|
|
95
|
+
const addTracksToPlaylist = (playlistId, sngIds) => (0, request_1.request)({ playlist_id: String(playlistId), songs: sngIds.map((id) => [String(id), 0]) }, 'playlist.addSongs');
|
|
96
|
+
exports.addTracksToPlaylist = addTracksToPlaylist;
|
|
97
|
+
/** Remove tracks from a playlist (`playlist.deleteSongs`). */
|
|
98
|
+
const removeTracksFromPlaylist = (playlistId, sngIds) => (0, request_1.request)({ playlist_id: String(playlistId), songs: sngIds.map((id) => [String(id), 0]) }, 'playlist.deleteSongs');
|
|
99
|
+
exports.removeTracksFromPlaylist = removeTracksFromPlaylist;
|
package/dist/api/index.d.ts
CHANGED
package/dist/api/index.js
CHANGED
|
@@ -21,3 +21,5 @@ __exportStar(require("./browse"), exports);
|
|
|
21
21
|
__exportStar(require("./preview"), exports);
|
|
22
22
|
__exportStar(require("./user"), exports);
|
|
23
23
|
__exportStar(require("./podcast"), exports);
|
|
24
|
+
__exportStar(require("./library"), exports);
|
|
25
|
+
__exportStar(require("./favorites"), exports);
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { playlistInfoMinimal, trackType } from '../types';
|
|
2
|
+
/** Envelope the gateway wraps these listings in. */
|
|
3
|
+
export interface GwList<T> {
|
|
4
|
+
data: T[];
|
|
5
|
+
count: number;
|
|
6
|
+
total: number;
|
|
7
|
+
filtered_count?: number;
|
|
8
|
+
checksum?: string;
|
|
9
|
+
}
|
|
10
|
+
/** A favourited artist, as the library returns it. */
|
|
11
|
+
export interface FavoriteArtist {
|
|
12
|
+
ART_ID: string;
|
|
13
|
+
ART_NAME: string;
|
|
14
|
+
ART_PICTURE: string;
|
|
15
|
+
/** when it was favourited — `YYYY-MM-DD HH:MM:SS` */
|
|
16
|
+
DATE_ADD?: string;
|
|
17
|
+
NB_ALBUM?: number;
|
|
18
|
+
NB_FAN?: number;
|
|
19
|
+
ARTIST_IS_DUMMY?: boolean;
|
|
20
|
+
__TYPE__?: string;
|
|
21
|
+
}
|
|
22
|
+
/** A favourited album, as the library returns it. */
|
|
23
|
+
export interface FavoriteAlbum {
|
|
24
|
+
ALB_ID: string;
|
|
25
|
+
ALB_TITLE: string;
|
|
26
|
+
ALB_PICTURE: string;
|
|
27
|
+
ART_ID?: string;
|
|
28
|
+
ART_NAME?: string;
|
|
29
|
+
DATE_ADD?: string;
|
|
30
|
+
NUMBER_TRACK?: number;
|
|
31
|
+
PHYSICAL_RELEASE_DATE?: string;
|
|
32
|
+
__TYPE__?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The account's own playlists (`playlist.getList`) — **including private ones**,
|
|
36
|
+
* which the public `/user/{id}/playlists` endpoint will not show you.
|
|
37
|
+
*
|
|
38
|
+
* @param userId defaults to the logged-in account
|
|
39
|
+
*/
|
|
40
|
+
export declare const getMyPlaylists: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<playlistInfoMinimal>>;
|
|
41
|
+
/**
|
|
42
|
+
* Loved tracks (`song.getFavorites`). Gateway track objects, so each carries a
|
|
43
|
+
* `TRACK_TOKEN` and can go straight to `resolveDownloadUrls`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const getMyFavoriteTracks: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<trackType>>;
|
|
46
|
+
/**
|
|
47
|
+
* Just the ids of every loved track (`song.getFavoriteIds`) — one small request
|
|
48
|
+
* for the whole set, for diffing a local library against the account.
|
|
49
|
+
*/
|
|
50
|
+
export declare const getMyFavoriteTrackIds: () => Promise<GwList<{
|
|
51
|
+
SNG_ID: string;
|
|
52
|
+
}>>;
|
|
53
|
+
/** Favourited albums (`album.getFavorites`). */
|
|
54
|
+
export declare const getMyFavoriteAlbums: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<FavoriteAlbum>>;
|
|
55
|
+
/** Favourited artists (`artist.getFavorites`). */
|
|
56
|
+
export declare const getMyFavoriteArtists: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<FavoriteArtist>>;
|
|
57
|
+
/** Playlists the account follows (`playlist.getFavorites`). */
|
|
58
|
+
export declare const getMyFavoritePlaylists: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<playlistInfoMinimal>>;
|
|
59
|
+
/** Favourited radios (`radio.getFavorites`). */
|
|
60
|
+
export declare const getMyFavoriteRadios: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<Record<string, any>>>;
|
|
61
|
+
/** Favourited podcast shows (`show.getFavorites`). */
|
|
62
|
+
export declare const getMyFavoriteShows: (userId?: string | number, nb?: number, start?: number) => Promise<GwList<Record<string, any>>>;
|
|
63
|
+
/**
|
|
64
|
+
* A "more like this" mix seeded from one track (`song.getSearchTrackMix`).
|
|
65
|
+
*
|
|
66
|
+
* Returns full gateway tracks **with `TRACK_TOKEN`s**, so unlike the public
|
|
67
|
+
* radio endpoints the results are immediately downloadable — no `getTrackInfo`
|
|
68
|
+
* round trip per hit.
|
|
69
|
+
*
|
|
70
|
+
* @param sngId the seed track's `SNG_ID`
|
|
71
|
+
*/
|
|
72
|
+
export declare const getTrackMix: (sngId: string, nb?: number, start?: number) => Promise<GwList<trackType>>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTrackMix = exports.getMyFavoriteShows = exports.getMyFavoriteRadios = exports.getMyFavoritePlaylists = exports.getMyFavoriteArtists = exports.getMyFavoriteAlbums = exports.getMyFavoriteTrackIds = exports.getMyFavoriteTracks = exports.getMyPlaylists = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* The **logged-in account's own library**, over the authenticated gateway.
|
|
6
|
+
*
|
|
7
|
+
* This is not the same surface as `src/api/user.ts`. Those functions read the
|
|
8
|
+
* *public* REST profile (`/user/{id}/tracks` …), which needs the profile to be
|
|
9
|
+
* public and shows only what that profile exposes. These read what the account
|
|
10
|
+
* itself can see — including a private library — and return gateway shapes, so
|
|
11
|
+
* tracks arrive with a `TRACK_TOKEN` and are directly downloadable.
|
|
12
|
+
*
|
|
13
|
+
* Every response here is account-scoped, so it lives in the per-session cache
|
|
14
|
+
* and is never shared between sessions.
|
|
15
|
+
*/
|
|
16
|
+
const request_1 = require("./request");
|
|
17
|
+
const api_1 = require("./api");
|
|
18
|
+
/** Resolve the caller's own user id when one wasn't supplied. */
|
|
19
|
+
const ownUserId = async (userId) => userId !== undefined ? String(userId) : String((await (0, api_1.getUser)()).USER_ID);
|
|
20
|
+
/**
|
|
21
|
+
* The account's own playlists (`playlist.getList`) — **including private ones**,
|
|
22
|
+
* which the public `/user/{id}/playlists` endpoint will not show you.
|
|
23
|
+
*
|
|
24
|
+
* @param userId defaults to the logged-in account
|
|
25
|
+
*/
|
|
26
|
+
const getMyPlaylists = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start, tab: 'all' }, 'playlist.getList');
|
|
27
|
+
exports.getMyPlaylists = getMyPlaylists;
|
|
28
|
+
/**
|
|
29
|
+
* Loved tracks (`song.getFavorites`). Gateway track objects, so each carries a
|
|
30
|
+
* `TRACK_TOKEN` and can go straight to `resolveDownloadUrls`.
|
|
31
|
+
*/
|
|
32
|
+
const getMyFavoriteTracks = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'song.getFavorites');
|
|
33
|
+
exports.getMyFavoriteTracks = getMyFavoriteTracks;
|
|
34
|
+
/**
|
|
35
|
+
* Just the ids of every loved track (`song.getFavoriteIds`) — one small request
|
|
36
|
+
* for the whole set, for diffing a local library against the account.
|
|
37
|
+
*/
|
|
38
|
+
const getMyFavoriteTrackIds = () => (0, request_1.request)({}, 'song.getFavoriteIds');
|
|
39
|
+
exports.getMyFavoriteTrackIds = getMyFavoriteTrackIds;
|
|
40
|
+
/** Favourited albums (`album.getFavorites`). */
|
|
41
|
+
const getMyFavoriteAlbums = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'album.getFavorites');
|
|
42
|
+
exports.getMyFavoriteAlbums = getMyFavoriteAlbums;
|
|
43
|
+
/** Favourited artists (`artist.getFavorites`). */
|
|
44
|
+
const getMyFavoriteArtists = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'artist.getFavorites');
|
|
45
|
+
exports.getMyFavoriteArtists = getMyFavoriteArtists;
|
|
46
|
+
/** Playlists the account follows (`playlist.getFavorites`). */
|
|
47
|
+
const getMyFavoritePlaylists = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'playlist.getFavorites');
|
|
48
|
+
exports.getMyFavoritePlaylists = getMyFavoritePlaylists;
|
|
49
|
+
/** Favourited radios (`radio.getFavorites`). */
|
|
50
|
+
const getMyFavoriteRadios = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'radio.getFavorites');
|
|
51
|
+
exports.getMyFavoriteRadios = getMyFavoriteRadios;
|
|
52
|
+
/** Favourited podcast shows (`show.getFavorites`). */
|
|
53
|
+
const getMyFavoriteShows = async (userId, nb = 50, start = 0) => (0, request_1.request)({ user_id: await ownUserId(userId), nb, start }, 'show.getFavorites');
|
|
54
|
+
exports.getMyFavoriteShows = getMyFavoriteShows;
|
|
55
|
+
/**
|
|
56
|
+
* A "more like this" mix seeded from one track (`song.getSearchTrackMix`).
|
|
57
|
+
*
|
|
58
|
+
* Returns full gateway tracks **with `TRACK_TOKEN`s**, so unlike the public
|
|
59
|
+
* radio endpoints the results are immediately downloadable — no `getTrackInfo`
|
|
60
|
+
* round trip per hit.
|
|
61
|
+
*
|
|
62
|
+
* @param sngId the seed track's `SNG_ID`
|
|
63
|
+
*/
|
|
64
|
+
const getTrackMix = (sngId, nb = 40, start = 0) => (0, request_1.request)({ sng_id: sngId, start, nb }, 'song.getSearchTrackMix');
|
|
65
|
+
exports.getTrackMix = getTrackMix;
|
package/package.json
CHANGED