@lucaperret/tidal-cli 1.1.2 → 1.2.3
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/README.md +34 -5
- package/dist/album.d.ts +4 -0
- package/dist/album.js +69 -50
- package/dist/artist.d.ts +7 -0
- package/dist/artist.js +139 -91
- package/dist/history.d.ts +3 -2
- package/dist/history.js +27 -17
- package/dist/index.js +96 -1
- package/dist/library.d.ts +25 -2
- package/dist/library.js +97 -48
- package/dist/mix.d.ts +4 -0
- package/dist/mix.js +59 -0
- package/dist/playback.d.ts +4 -0
- package/dist/playback.js +62 -46
- package/dist/playlist.d.ts +43 -0
- package/dist/playlist.js +183 -104
- package/dist/recommend.d.ts +4 -1
- package/dist/recommend.js +71 -19
- package/dist/saved.d.ts +16 -0
- package/dist/saved.js +107 -0
- package/dist/search-history.d.ts +13 -0
- package/dist/search-history.js +94 -0
- package/dist/search.d.ts +4 -2
- package/dist/search.js +66 -45
- package/dist/session.js +17 -7
- package/dist/share.d.ts +5 -0
- package/dist/share.js +53 -0
- package/dist/track.d.ts +14 -0
- package/dist/track.js +128 -91
- package/dist/types.d.ts +158 -0
- package/dist/types.js +4 -0
- package/dist/user.d.ts +3 -0
- package/dist/user.js +27 -18
- package/package.json +8 -6
package/dist/history.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRecentlyAddedData = getRecentlyAddedData;
|
|
3
4
|
exports.getRecentlyAdded = getRecentlyAdded;
|
|
4
5
|
const auth_1 = require("./auth");
|
|
5
6
|
const endpointMap = {
|
|
@@ -12,9 +13,7 @@ const includeTypeMap = {
|
|
|
12
13
|
albums: 'albums',
|
|
13
14
|
artists: 'artists',
|
|
14
15
|
};
|
|
15
|
-
async function
|
|
16
|
-
const client = await (0, auth_1.getApiClient)();
|
|
17
|
-
const countryCode = await (0, auth_1.getCountryCode)();
|
|
16
|
+
async function getRecentlyAddedData(type, client, countryCode) {
|
|
18
17
|
const { data, error } = await client.GET(endpointMap[type], {
|
|
19
18
|
params: {
|
|
20
19
|
path: { id: 'me' },
|
|
@@ -26,8 +25,7 @@ async function getRecentlyAdded(type, json) {
|
|
|
26
25
|
},
|
|
27
26
|
});
|
|
28
27
|
if (error || !data) {
|
|
29
|
-
|
|
30
|
-
process.exit(1);
|
|
28
|
+
throw new Error(`Failed to get recently added ${type} — ${JSON.stringify(error)}`);
|
|
31
29
|
}
|
|
32
30
|
const included = data.included ?? [];
|
|
33
31
|
const items = included
|
|
@@ -51,19 +49,31 @@ async function getRecentlyAdded(type, json) {
|
|
|
51
49
|
}
|
|
52
50
|
}
|
|
53
51
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
52
|
+
return items;
|
|
53
|
+
}
|
|
54
|
+
async function getRecentlyAdded(type, json) {
|
|
55
|
+
const client = await (0, auth_1.getApiClient)();
|
|
56
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
57
|
+
try {
|
|
58
|
+
const items = await getRecentlyAddedData(type, client, countryCode);
|
|
59
|
+
if (json) {
|
|
60
|
+
console.log(JSON.stringify(items, null, 2));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (items.length === 0) {
|
|
64
|
+
console.log(`No recently added ${type} found.`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
console.log(`\nRecently added ${type}:\n`);
|
|
68
|
+
for (const item of items) {
|
|
69
|
+
const date = item.addedAt ? ` (added: ${item.addedAt})` : '';
|
|
70
|
+
console.log(` [${item.id}] ${item.name}${date}`);
|
|
71
|
+
}
|
|
72
|
+
console.log();
|
|
61
73
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
console.log(` [${item.id}] ${item.name}${date}`);
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error(`Error: ${err.message}`);
|
|
76
|
+
process.exit(1);
|
|
66
77
|
}
|
|
67
|
-
console.log();
|
|
68
78
|
}
|
|
69
79
|
//# sourceMappingURL=history.js.map
|
package/dist/index.js
CHANGED
|
@@ -18,8 +18,22 @@ const artist_1 = require("./artist");
|
|
|
18
18
|
const track_1 = require("./track");
|
|
19
19
|
const album_1 = require("./album");
|
|
20
20
|
const recommend_1 = require("./recommend");
|
|
21
|
+
const mix_1 = require("./mix");
|
|
21
22
|
const user_1 = require("./user");
|
|
22
23
|
const history_1 = require("./history");
|
|
24
|
+
const search_history_1 = require("./search-history");
|
|
25
|
+
const saved_1 = require("./saved");
|
|
26
|
+
const share_1 = require("./share");
|
|
27
|
+
const MIX_CATEGORIES = ['daily', 'discovery', 'new-release', 'offline'];
|
|
28
|
+
function parseMixCategory(value) {
|
|
29
|
+
if (!value)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (!MIX_CATEGORIES.includes(value)) {
|
|
32
|
+
console.error(`Error: invalid mix category "${value}". Use one of: ${MIX_CATEGORIES.join(', ')}`);
|
|
33
|
+
process.exit(2);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
23
37
|
const program = new commander_1.Command();
|
|
24
38
|
program
|
|
25
39
|
.name('tidal-cli')
|
|
@@ -85,6 +99,24 @@ searchCmd
|
|
|
85
99
|
.action(wrapAction(async (genre) => {
|
|
86
100
|
await (0, search_1.search)('playlist', genre || 'top hits', getJson());
|
|
87
101
|
}));
|
|
102
|
+
searchCmd
|
|
103
|
+
.command('history')
|
|
104
|
+
.description('List your search history')
|
|
105
|
+
.action(wrapAction(async () => {
|
|
106
|
+
await (0, search_history_1.listSearchHistory)(getJson());
|
|
107
|
+
}));
|
|
108
|
+
searchCmd
|
|
109
|
+
.command('history-delete <entry-id>')
|
|
110
|
+
.description('Delete a single search history entry')
|
|
111
|
+
.action(wrapAction(async (entryId) => {
|
|
112
|
+
await (0, search_history_1.deleteSearchHistoryEntry)(entryId, getJson());
|
|
113
|
+
}));
|
|
114
|
+
searchCmd
|
|
115
|
+
.command('history-clear')
|
|
116
|
+
.description('Clear all search history entries')
|
|
117
|
+
.action(wrapAction(async () => {
|
|
118
|
+
await (0, search_history_1.clearSearchHistory)(getJson());
|
|
119
|
+
}));
|
|
88
120
|
// Artist
|
|
89
121
|
const artistCmd = program
|
|
90
122
|
.command('artist')
|
|
@@ -167,8 +199,71 @@ albumCmd
|
|
|
167
199
|
program
|
|
168
200
|
.command('recommend')
|
|
169
201
|
.description('Get personalized recommendations')
|
|
202
|
+
.option('--type <category>', `Mix category: ${MIX_CATEGORIES.join(', ')}`)
|
|
203
|
+
.action(wrapAction(async (opts) => {
|
|
204
|
+
await (0, recommend_1.getRecommendations)(parseMixCategory(opts.type), getJson());
|
|
205
|
+
}));
|
|
206
|
+
// Mix
|
|
207
|
+
const mixCmd = program
|
|
208
|
+
.command('mix')
|
|
209
|
+
.description('Browse personalized mix contents');
|
|
210
|
+
mixCmd
|
|
211
|
+
.command('items <mix-id>')
|
|
212
|
+
.description('Get items inside a specific mix')
|
|
213
|
+
.requiredOption('--type <category>', `Mix category: ${MIX_CATEGORIES.join(', ')}`)
|
|
214
|
+
.action(wrapAction(async (mixId, opts) => {
|
|
215
|
+
const cat = parseMixCategory(opts.type);
|
|
216
|
+
if (!cat)
|
|
217
|
+
return;
|
|
218
|
+
await (0, mix_1.getMixItems)(cat, mixId, getJson());
|
|
219
|
+
}));
|
|
220
|
+
// Share
|
|
221
|
+
program
|
|
222
|
+
.command('share <type> <id>')
|
|
223
|
+
.description('Create a share link for a track or album (type: track | album)')
|
|
224
|
+
.action(wrapAction(async (type, id) => {
|
|
225
|
+
const normalized = type === 'track' ? 'tracks' : type === 'album' ? 'albums' : null;
|
|
226
|
+
if (!normalized) {
|
|
227
|
+
console.error('Error: type must be "track" or "album"');
|
|
228
|
+
process.exit(2);
|
|
229
|
+
}
|
|
230
|
+
await (0, share_1.createShare)(normalized, id, getJson());
|
|
231
|
+
}));
|
|
232
|
+
// Saved (save for later)
|
|
233
|
+
const savedCmd = program
|
|
234
|
+
.command('saved')
|
|
235
|
+
.description('Manage your save-for-later collection');
|
|
236
|
+
savedCmd
|
|
237
|
+
.command('list')
|
|
238
|
+
.description('List items saved for later')
|
|
170
239
|
.action(wrapAction(async () => {
|
|
171
|
-
await (0,
|
|
240
|
+
await (0, saved_1.listSavedItems)(getJson());
|
|
241
|
+
}));
|
|
242
|
+
savedCmd
|
|
243
|
+
.command('add')
|
|
244
|
+
.description('Save an item for later')
|
|
245
|
+
.requiredOption('--type <type>', 'Item type: tracks, albums, artists, playlists, videos')
|
|
246
|
+
.requiredOption('--id <id>', 'Item ID')
|
|
247
|
+
.action(wrapAction(async (opts) => {
|
|
248
|
+
const allowed = ['tracks', 'albums', 'artists', 'playlists', 'videos'];
|
|
249
|
+
if (!allowed.includes(opts.type)) {
|
|
250
|
+
console.error(`Error: invalid type. Use one of: ${allowed.join(', ')}`);
|
|
251
|
+
process.exit(2);
|
|
252
|
+
}
|
|
253
|
+
await (0, saved_1.addSavedItem)(opts.type, opts.id, getJson());
|
|
254
|
+
}));
|
|
255
|
+
savedCmd
|
|
256
|
+
.command('remove')
|
|
257
|
+
.description('Remove an item from saved')
|
|
258
|
+
.requiredOption('--type <type>', 'Item type')
|
|
259
|
+
.requiredOption('--id <id>', 'Item ID')
|
|
260
|
+
.action(wrapAction(async (opts) => {
|
|
261
|
+
const allowed = ['tracks', 'albums', 'artists', 'playlists', 'videos'];
|
|
262
|
+
if (!allowed.includes(opts.type)) {
|
|
263
|
+
console.error(`Error: invalid type. Use one of: ${allowed.join(', ')}`);
|
|
264
|
+
process.exit(2);
|
|
265
|
+
}
|
|
266
|
+
await (0, saved_1.removeSavedItem)(opts.type, opts.id, getJson());
|
|
172
267
|
}));
|
|
173
268
|
// User
|
|
174
269
|
const userCmd = program
|
package/dist/library.d.ts
CHANGED
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
type LibraryResourceType
|
|
1
|
+
import type { LibraryResourceType } from './types';
|
|
2
|
+
export type { LibraryResourceType };
|
|
3
|
+
export declare function addToLibraryData(resourceType: LibraryResourceType, resourceId: string, client: any): Promise<{
|
|
4
|
+
resourceType: string;
|
|
5
|
+
resourceId: string;
|
|
6
|
+
added: boolean;
|
|
7
|
+
}>;
|
|
2
8
|
export declare function addToLibrary(resourceType: LibraryResourceType, resourceId: string, json: boolean): Promise<void>;
|
|
9
|
+
export declare function removeFromLibraryData(resourceType: LibraryResourceType, resourceId: string, client: any): Promise<{
|
|
10
|
+
resourceType: string;
|
|
11
|
+
resourceId: string;
|
|
12
|
+
removed: boolean;
|
|
13
|
+
}>;
|
|
3
14
|
export declare function removeFromLibrary(resourceType: LibraryResourceType, resourceId: string, json: boolean): Promise<void>;
|
|
15
|
+
export declare function listFavoritedPlaylistsData(client: any): Promise<Array<{
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
numberOfItems?: number;
|
|
19
|
+
}>>;
|
|
4
20
|
export declare function listFavoritedPlaylists(json: boolean): Promise<void>;
|
|
21
|
+
export declare function addPlaylistToFavoritesData(playlistId: string, client: any): Promise<{
|
|
22
|
+
playlistId: string;
|
|
23
|
+
added: boolean;
|
|
24
|
+
}>;
|
|
5
25
|
export declare function addPlaylistToFavorites(playlistId: string, json: boolean): Promise<void>;
|
|
26
|
+
export declare function removePlaylistFromFavoritesData(playlistId: string, client: any): Promise<{
|
|
27
|
+
playlistId: string;
|
|
28
|
+
removed: boolean;
|
|
29
|
+
}>;
|
|
6
30
|
export declare function removePlaylistFromFavorites(playlistId: string, json: boolean): Promise<void>;
|
|
7
|
-
export {};
|
package/dist/library.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.addToLibraryData = addToLibraryData;
|
|
3
4
|
exports.addToLibrary = addToLibrary;
|
|
5
|
+
exports.removeFromLibraryData = removeFromLibraryData;
|
|
4
6
|
exports.removeFromLibrary = removeFromLibrary;
|
|
7
|
+
exports.listFavoritedPlaylistsData = listFavoritedPlaylistsData;
|
|
5
8
|
exports.listFavoritedPlaylists = listFavoritedPlaylists;
|
|
9
|
+
exports.addPlaylistToFavoritesData = addPlaylistToFavoritesData;
|
|
6
10
|
exports.addPlaylistToFavorites = addPlaylistToFavorites;
|
|
11
|
+
exports.removePlaylistFromFavoritesData = removePlaylistFromFavoritesData;
|
|
7
12
|
exports.removePlaylistFromFavorites = removePlaylistFromFavorites;
|
|
8
13
|
const auth_1 = require("./auth");
|
|
9
14
|
const collectionEndpoints = {
|
|
@@ -12,8 +17,7 @@ const collectionEndpoints = {
|
|
|
12
17
|
track: { path: '/userCollectionTracks/{id}/relationships/items', type: 'tracks' },
|
|
13
18
|
video: { path: '/userCollectionVideos/{id}/relationships/items', type: 'videos' },
|
|
14
19
|
};
|
|
15
|
-
async function
|
|
16
|
-
const client = await (0, auth_1.getApiClient)();
|
|
20
|
+
async function addToLibraryData(resourceType, resourceId, client) {
|
|
17
21
|
const endpoint = collectionEndpoints[resourceType];
|
|
18
22
|
const { error } = await client.POST(endpoint.path, {
|
|
19
23
|
params: { path: { id: 'me' } },
|
|
@@ -22,17 +26,26 @@ async function addToLibrary(resourceType, resourceId, json) {
|
|
|
22
26
|
},
|
|
23
27
|
});
|
|
24
28
|
if (error) {
|
|
25
|
-
|
|
26
|
-
process.exit(1);
|
|
29
|
+
throw new Error(`Failed to add ${resourceType} to library — ${JSON.stringify(error)}`);
|
|
27
30
|
}
|
|
28
|
-
|
|
29
|
-
console.log(JSON.stringify({ resourceType, resourceId, added: true }, null, 2));
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
console.log(`\n${capitalize(resourceType)} ${resourceId} added to your library.`);
|
|
31
|
+
return { resourceType, resourceId, added: true };
|
|
33
32
|
}
|
|
34
|
-
async function
|
|
33
|
+
async function addToLibrary(resourceType, resourceId, json) {
|
|
35
34
|
const client = await (0, auth_1.getApiClient)();
|
|
35
|
+
try {
|
|
36
|
+
const result = await addToLibraryData(resourceType, resourceId, client);
|
|
37
|
+
if (json) {
|
|
38
|
+
console.log(JSON.stringify(result, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.log(`\n${capitalize(resourceType)} ${resourceId} added to your library.`);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.error(`Error: ${err.message}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function removeFromLibraryData(resourceType, resourceId, client) {
|
|
36
49
|
const endpoint = collectionEndpoints[resourceType];
|
|
37
50
|
const { error } = await client.DELETE(endpoint.path, {
|
|
38
51
|
params: { path: { id: 'me' } },
|
|
@@ -41,17 +54,26 @@ async function removeFromLibrary(resourceType, resourceId, json) {
|
|
|
41
54
|
},
|
|
42
55
|
});
|
|
43
56
|
if (error) {
|
|
44
|
-
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
|
-
if (json) {
|
|
48
|
-
console.log(JSON.stringify({ resourceType, resourceId, removed: true }, null, 2));
|
|
49
|
-
return;
|
|
57
|
+
throw new Error(`Failed to remove ${resourceType} from library — ${JSON.stringify(error)}`);
|
|
50
58
|
}
|
|
51
|
-
|
|
59
|
+
return { resourceType, resourceId, removed: true };
|
|
52
60
|
}
|
|
53
|
-
async function
|
|
61
|
+
async function removeFromLibrary(resourceType, resourceId, json) {
|
|
54
62
|
const client = await (0, auth_1.getApiClient)();
|
|
63
|
+
try {
|
|
64
|
+
const result = await removeFromLibraryData(resourceType, resourceId, client);
|
|
65
|
+
if (json) {
|
|
66
|
+
console.log(JSON.stringify(result, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(`\n${capitalize(resourceType)} ${resourceId} removed from your library.`);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
console.error(`Error: ${err.message}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function listFavoritedPlaylistsData(client) {
|
|
55
77
|
const { data, error } = await client.GET('/userCollectionPlaylists/{id}/relationships/items', {
|
|
56
78
|
params: {
|
|
57
79
|
path: { id: 'me' },
|
|
@@ -61,11 +83,10 @@ async function listFavoritedPlaylists(json) {
|
|
|
61
83
|
},
|
|
62
84
|
});
|
|
63
85
|
if (error || !data) {
|
|
64
|
-
|
|
65
|
-
process.exit(1);
|
|
86
|
+
throw new Error(`Failed to list favorited playlists — ${JSON.stringify(error)}`);
|
|
66
87
|
}
|
|
67
88
|
const included = data.included ?? [];
|
|
68
|
-
|
|
89
|
+
return included
|
|
69
90
|
.filter((item) => item.type === 'playlists')
|
|
70
91
|
.map((item) => {
|
|
71
92
|
const attrs = item.attributes;
|
|
@@ -75,22 +96,31 @@ async function listFavoritedPlaylists(json) {
|
|
|
75
96
|
numberOfItems: attrs?.numberOfItems,
|
|
76
97
|
};
|
|
77
98
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
99
|
+
}
|
|
100
|
+
async function listFavoritedPlaylists(json) {
|
|
101
|
+
const client = await (0, auth_1.getApiClient)();
|
|
102
|
+
try {
|
|
103
|
+
const playlists = await listFavoritedPlaylistsData(client);
|
|
104
|
+
if (json) {
|
|
105
|
+
console.log(JSON.stringify(playlists, null, 2));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (playlists.length === 0) {
|
|
109
|
+
console.log('No favorited playlists found.');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
console.log('\nFavorited playlists:\n');
|
|
113
|
+
for (const p of playlists) {
|
|
114
|
+
console.log(` [${p.id}] ${p.name} (${p.numberOfItems ?? 0} items)`);
|
|
115
|
+
}
|
|
116
|
+
console.log();
|
|
85
117
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.error(`Error: ${err.message}`);
|
|
120
|
+
process.exit(1);
|
|
89
121
|
}
|
|
90
|
-
console.log();
|
|
91
122
|
}
|
|
92
|
-
async function
|
|
93
|
-
const client = await (0, auth_1.getApiClient)();
|
|
123
|
+
async function addPlaylistToFavoritesData(playlistId, client) {
|
|
94
124
|
const { error } = await client.POST('/userCollectionPlaylists/{id}/relationships/items', {
|
|
95
125
|
params: { path: { id: 'me' } },
|
|
96
126
|
body: {
|
|
@@ -98,17 +128,26 @@ async function addPlaylistToFavorites(playlistId, json) {
|
|
|
98
128
|
},
|
|
99
129
|
});
|
|
100
130
|
if (error) {
|
|
101
|
-
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
if (json) {
|
|
105
|
-
console.log(JSON.stringify({ playlistId, added: true }, null, 2));
|
|
106
|
-
return;
|
|
131
|
+
throw new Error(`Failed to add playlist to favorites — ${JSON.stringify(error)}`);
|
|
107
132
|
}
|
|
108
|
-
|
|
133
|
+
return { playlistId, added: true };
|
|
109
134
|
}
|
|
110
|
-
async function
|
|
135
|
+
async function addPlaylistToFavorites(playlistId, json) {
|
|
111
136
|
const client = await (0, auth_1.getApiClient)();
|
|
137
|
+
try {
|
|
138
|
+
const result = await addPlaylistToFavoritesData(playlistId, client);
|
|
139
|
+
if (json) {
|
|
140
|
+
console.log(JSON.stringify(result, null, 2));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
console.log(`\nPlaylist ${playlistId} added to favorites.`);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
console.error(`Error: ${err.message}`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function removePlaylistFromFavoritesData(playlistId, client) {
|
|
112
151
|
const { error } = await client.DELETE('/userCollectionPlaylists/{id}/relationships/items', {
|
|
113
152
|
params: { path: { id: 'me' } },
|
|
114
153
|
body: {
|
|
@@ -116,14 +155,24 @@ async function removePlaylistFromFavorites(playlistId, json) {
|
|
|
116
155
|
},
|
|
117
156
|
});
|
|
118
157
|
if (error) {
|
|
119
|
-
|
|
120
|
-
process.exit(1);
|
|
158
|
+
throw new Error(`Failed to remove playlist from favorites — ${JSON.stringify(error)}`);
|
|
121
159
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
160
|
+
return { playlistId, removed: true };
|
|
161
|
+
}
|
|
162
|
+
async function removePlaylistFromFavorites(playlistId, json) {
|
|
163
|
+
const client = await (0, auth_1.getApiClient)();
|
|
164
|
+
try {
|
|
165
|
+
const result = await removePlaylistFromFavoritesData(playlistId, client);
|
|
166
|
+
if (json) {
|
|
167
|
+
console.log(JSON.stringify(result, null, 2));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
console.log(`\nPlaylist ${playlistId} removed from favorites.`);
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
console.error(`Error: ${err.message}`);
|
|
174
|
+
process.exit(1);
|
|
125
175
|
}
|
|
126
|
-
console.log(`\nPlaylist ${playlistId} removed from favorites.`);
|
|
127
176
|
}
|
|
128
177
|
function capitalize(s) {
|
|
129
178
|
return s.charAt(0).toUpperCase() + s.slice(1);
|
package/dist/mix.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MixCategory, MixItem } from './types';
|
|
2
|
+
export type { MixItem };
|
|
3
|
+
export declare function getMixItemsData(category: MixCategory, mixId: string, client: any, countryCode: string): Promise<MixItem[]>;
|
|
4
|
+
export declare function getMixItems(category: MixCategory, mixId: string, json: boolean): Promise<void>;
|
package/dist/mix.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getMixItemsData = getMixItemsData;
|
|
4
|
+
exports.getMixItems = getMixItems;
|
|
5
|
+
const auth_1 = require("./auth");
|
|
6
|
+
const categoryEndpoints = {
|
|
7
|
+
daily: '/userDailyMixes/{id}/relationships/items',
|
|
8
|
+
discovery: '/userDiscoveryMixes/{id}/relationships/items',
|
|
9
|
+
'new-release': '/userNewReleaseMixes/{id}/relationships/items',
|
|
10
|
+
offline: '/userOfflineMixes/{id}/relationships/items',
|
|
11
|
+
};
|
|
12
|
+
async function getMixItemsData(category, mixId, client, countryCode) {
|
|
13
|
+
const { data, error } = await client.GET(categoryEndpoints[category], {
|
|
14
|
+
params: {
|
|
15
|
+
path: { id: mixId },
|
|
16
|
+
query: {
|
|
17
|
+
countryCode,
|
|
18
|
+
include: ['items'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
if (error || !data) {
|
|
23
|
+
throw new Error(`Failed to get mix items — ${JSON.stringify(error)}`);
|
|
24
|
+
}
|
|
25
|
+
const included = data.included ?? [];
|
|
26
|
+
return included.map((item) => {
|
|
27
|
+
const attrs = item.attributes ?? {};
|
|
28
|
+
return {
|
|
29
|
+
id: item.id,
|
|
30
|
+
type: item.type,
|
|
31
|
+
name: attrs.title ?? attrs.name ?? 'Untitled',
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function getMixItems(category, mixId, json) {
|
|
36
|
+
const client = await (0, auth_1.getApiClient)();
|
|
37
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
38
|
+
try {
|
|
39
|
+
const items = await getMixItemsData(category, mixId, client, countryCode);
|
|
40
|
+
if (json) {
|
|
41
|
+
console.log(JSON.stringify(items, null, 2));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (items.length === 0) {
|
|
45
|
+
console.log('No items found in this mix.');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(`\n${category} mix [${mixId}] items:\n`);
|
|
49
|
+
for (const item of items) {
|
|
50
|
+
console.log(` [${item.id}] (${item.type}) ${item.name}`);
|
|
51
|
+
}
|
|
52
|
+
console.log();
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error(`Error: ${err.message}`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=mix.js.map
|
package/dist/playback.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import type { PlaybackInfo, PlaybackUrl } from './types';
|
|
2
|
+
export type { PlaybackInfo, PlaybackUrl };
|
|
3
|
+
export declare function playbackInfoData(trackId: string, quality: string, client: any): Promise<PlaybackInfo>;
|
|
1
4
|
export declare function playbackInfo(trackId: string, quality: string, json: boolean): Promise<void>;
|
|
5
|
+
export declare function playbackUrlData(trackId: string, quality: string, client: any): Promise<PlaybackUrl>;
|
|
2
6
|
export declare function playbackUrl(trackId: string, quality: string, json: boolean): Promise<void>;
|
|
3
7
|
export declare function playbackPlay(trackId: string, quality: string): Promise<void>;
|