@lucaperret/tidal-cli 1.1.2 → 1.2.2
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 +13 -1
- 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/track.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTrackInfoData = getTrackInfoData;
|
|
3
4
|
exports.getTrackInfo = getTrackInfo;
|
|
5
|
+
exports.getTrackRadioData = getTrackRadioData;
|
|
4
6
|
exports.getTrackRadio = getTrackRadio;
|
|
7
|
+
exports.getTrackByIsrcData = getTrackByIsrcData;
|
|
5
8
|
exports.getTrackByIsrc = getTrackByIsrc;
|
|
9
|
+
exports.getSimilarTracksData = getSimilarTracksData;
|
|
6
10
|
exports.getSimilarTracks = getSimilarTracks;
|
|
7
11
|
const auth_1 = require("./auth");
|
|
8
12
|
function formatDuration(isoDuration) {
|
|
@@ -16,20 +20,18 @@ function formatDuration(isoDuration) {
|
|
|
16
20
|
const s = (match[3] ?? '0').padStart(2, '0');
|
|
17
21
|
return `${h}${m}:${s}`;
|
|
18
22
|
}
|
|
19
|
-
async function
|
|
20
|
-
const client = await (0, auth_1.getApiClient)();
|
|
23
|
+
async function getTrackInfoData(trackId, client, countryCode) {
|
|
21
24
|
const { data, error } = await client.GET('/tracks/{id}', {
|
|
22
25
|
params: {
|
|
23
26
|
path: { id: trackId },
|
|
24
27
|
query: {
|
|
25
|
-
countryCode
|
|
28
|
+
countryCode,
|
|
26
29
|
include: ['artists', 'albums'],
|
|
27
30
|
},
|
|
28
31
|
},
|
|
29
32
|
});
|
|
30
33
|
if (error || !data) {
|
|
31
|
-
|
|
32
|
-
process.exit(1);
|
|
34
|
+
throw new Error(`Failed to get track info — ${JSON.stringify(error)}`);
|
|
33
35
|
}
|
|
34
36
|
const attrs = data.data?.attributes ?? {};
|
|
35
37
|
const included = data.included ?? [];
|
|
@@ -38,25 +40,23 @@ async function getTrackInfo(trackId, json) {
|
|
|
38
40
|
.map((item) => item.attributes?.name ?? item.id);
|
|
39
41
|
const album = included.find((item) => item.type === 'albums');
|
|
40
42
|
const albumName = album?.attributes?.title ?? undefined;
|
|
41
|
-
// Fetch cover art if we have an album
|
|
42
43
|
let coverUrl;
|
|
43
44
|
if (album?.id) {
|
|
44
45
|
try {
|
|
45
46
|
const { data: artData } = await client.GET('/albums/{id}/relationships/coverArt', {
|
|
46
47
|
params: {
|
|
47
48
|
path: { id: album.id },
|
|
48
|
-
query: { countryCode
|
|
49
|
+
query: { countryCode, include: ['coverArt'] },
|
|
49
50
|
},
|
|
50
51
|
});
|
|
51
52
|
const artwork = (artData?.included ?? []).find((i) => i.type === 'artworks');
|
|
52
53
|
const files = artwork?.attributes?.files ?? [];
|
|
53
|
-
// Pick 640x640 or the largest available
|
|
54
54
|
const preferred = files.find((f) => f.meta?.width === 640) ?? files[0];
|
|
55
55
|
coverUrl = preferred?.href;
|
|
56
56
|
}
|
|
57
57
|
catch { }
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
return {
|
|
60
60
|
id: trackId,
|
|
61
61
|
title: attrs.title ?? 'Unknown',
|
|
62
62
|
artists,
|
|
@@ -69,50 +69,58 @@ async function getTrackInfo(trackId, json) {
|
|
|
69
69
|
explicit: attrs.explicit,
|
|
70
70
|
coverUrl,
|
|
71
71
|
};
|
|
72
|
-
if (json) {
|
|
73
|
-
console.log(JSON.stringify(result, null, 2));
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
console.log(`\nTrack: [${result.id}] ${result.title}`);
|
|
77
|
-
if (result.artists.length > 0)
|
|
78
|
-
console.log(` Artists: ${result.artists.join(', ')}`);
|
|
79
|
-
if (result.album)
|
|
80
|
-
console.log(` Album: ${result.album}`);
|
|
81
|
-
if (result.duration)
|
|
82
|
-
console.log(` Duration: ${result.duration}`);
|
|
83
|
-
if (result.isrc)
|
|
84
|
-
console.log(` ISRC: ${result.isrc}`);
|
|
85
|
-
if (result.bpm !== undefined)
|
|
86
|
-
console.log(` BPM: ${result.bpm}`);
|
|
87
|
-
if (result.key !== undefined)
|
|
88
|
-
console.log(` Key: ${result.key}`);
|
|
89
|
-
if (result.popularity !== undefined)
|
|
90
|
-
console.log(` Popularity: ${result.popularity}`);
|
|
91
|
-
if (result.explicit !== undefined)
|
|
92
|
-
console.log(` Explicit: ${result.explicit}`);
|
|
93
|
-
if (result.coverUrl)
|
|
94
|
-
console.log(` Cover: ${result.coverUrl}`);
|
|
95
|
-
console.log();
|
|
96
72
|
}
|
|
97
|
-
async function
|
|
73
|
+
async function getTrackInfo(trackId, json) {
|
|
98
74
|
const client = await (0, auth_1.getApiClient)();
|
|
75
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
76
|
+
try {
|
|
77
|
+
const result = await getTrackInfoData(trackId, client, countryCode);
|
|
78
|
+
if (json) {
|
|
79
|
+
console.log(JSON.stringify(result, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
console.log(`\nTrack: [${result.id}] ${result.title}`);
|
|
83
|
+
if (result.artists.length > 0)
|
|
84
|
+
console.log(` Artists: ${result.artists.join(', ')}`);
|
|
85
|
+
if (result.album)
|
|
86
|
+
console.log(` Album: ${result.album}`);
|
|
87
|
+
if (result.duration)
|
|
88
|
+
console.log(` Duration: ${result.duration}`);
|
|
89
|
+
if (result.isrc)
|
|
90
|
+
console.log(` ISRC: ${result.isrc}`);
|
|
91
|
+
if (result.bpm !== undefined)
|
|
92
|
+
console.log(` BPM: ${result.bpm}`);
|
|
93
|
+
if (result.key !== undefined)
|
|
94
|
+
console.log(` Key: ${result.key}`);
|
|
95
|
+
if (result.popularity !== undefined)
|
|
96
|
+
console.log(` Popularity: ${result.popularity}`);
|
|
97
|
+
if (result.explicit !== undefined)
|
|
98
|
+
console.log(` Explicit: ${result.explicit}`);
|
|
99
|
+
if (result.coverUrl)
|
|
100
|
+
console.log(` Cover: ${result.coverUrl}`);
|
|
101
|
+
console.log();
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
console.error(`Error: ${err.message}`);
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
async function getTrackRadioData(trackId, client, countryCode) {
|
|
99
109
|
const { data, error } = await client.GET('/tracks/{id}/relationships/radio', {
|
|
100
110
|
params: {
|
|
101
111
|
path: { id: trackId },
|
|
102
112
|
query: {
|
|
103
|
-
countryCode
|
|
113
|
+
countryCode,
|
|
104
114
|
include: ['radio'],
|
|
105
115
|
},
|
|
106
116
|
},
|
|
107
117
|
});
|
|
108
118
|
if (error || !data) {
|
|
109
|
-
|
|
110
|
-
process.exit(1);
|
|
119
|
+
throw new Error(`Failed to get track radio — ${JSON.stringify(error)}`);
|
|
111
120
|
}
|
|
112
|
-
// Radio returns playlists (mix playlists), not individual tracks
|
|
113
121
|
const radioData = data.data ?? [];
|
|
114
122
|
const included = data.included ?? [];
|
|
115
|
-
|
|
123
|
+
return radioData.map((item) => {
|
|
116
124
|
const incl = included.find((i) => i.id === item.id && i.type === 'playlists');
|
|
117
125
|
const attrs = incl?.attributes ?? {};
|
|
118
126
|
return {
|
|
@@ -122,38 +130,47 @@ async function getTrackRadio(trackId, json) {
|
|
|
122
130
|
numberOfItems: attrs.numberOfItems,
|
|
123
131
|
};
|
|
124
132
|
});
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
}
|
|
134
|
+
async function getTrackRadio(trackId, json) {
|
|
135
|
+
const client = await (0, auth_1.getApiClient)();
|
|
136
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
137
|
+
try {
|
|
138
|
+
const playlists = await getTrackRadioData(trackId, client, countryCode);
|
|
139
|
+
if (json) {
|
|
140
|
+
console.log(JSON.stringify(playlists, null, 2));
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (playlists.length === 0) {
|
|
144
|
+
console.log(`No radio found for track ${trackId}.`);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
console.log(`\nRadio for track ${trackId}:\n`);
|
|
148
|
+
for (const p of playlists) {
|
|
149
|
+
console.log(` [${p.id}] ${p.name ?? 'Radio Mix'}${p.numberOfItems ? ` (${p.numberOfItems} tracks)` : ''}`);
|
|
150
|
+
}
|
|
151
|
+
console.log();
|
|
132
152
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
153
|
+
catch (err) {
|
|
154
|
+
console.error(`Error: ${err.message}`);
|
|
155
|
+
process.exit(1);
|
|
136
156
|
}
|
|
137
|
-
console.log();
|
|
138
157
|
}
|
|
139
|
-
async function
|
|
140
|
-
const client = await (0, auth_1.getApiClient)();
|
|
158
|
+
async function getTrackByIsrcData(isrc, client, countryCode) {
|
|
141
159
|
const { data, error } = await client.GET('/tracks', {
|
|
142
160
|
params: {
|
|
143
161
|
query: {
|
|
144
|
-
countryCode
|
|
162
|
+
countryCode,
|
|
145
163
|
'filter[isrc]': [isrc],
|
|
146
164
|
include: ['artists'],
|
|
147
165
|
},
|
|
148
166
|
},
|
|
149
167
|
});
|
|
150
168
|
if (error || !data) {
|
|
151
|
-
|
|
152
|
-
process.exit(1);
|
|
169
|
+
throw new Error(`Failed to get track by ISRC — ${JSON.stringify(error)}`);
|
|
153
170
|
}
|
|
154
171
|
const items = data.data ?? [];
|
|
155
172
|
const included = data.included ?? [];
|
|
156
|
-
|
|
173
|
+
return items.map((item) => {
|
|
157
174
|
const attrs = item.attributes;
|
|
158
175
|
const artistRels = item.relationships?.artists?.data ?? [];
|
|
159
176
|
const artistNames = artistRels.map((rel) => {
|
|
@@ -169,41 +186,50 @@ async function getTrackByIsrc(isrc, json) {
|
|
|
169
186
|
popularity: attrs?.popularity,
|
|
170
187
|
};
|
|
171
188
|
});
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
189
|
+
}
|
|
190
|
+
async function getTrackByIsrc(isrc, json) {
|
|
191
|
+
const client = await (0, auth_1.getApiClient)();
|
|
192
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
193
|
+
try {
|
|
194
|
+
const tracks = await getTrackByIsrcData(isrc, client, countryCode);
|
|
195
|
+
if (json) {
|
|
196
|
+
console.log(JSON.stringify(tracks, null, 2));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (tracks.length === 0) {
|
|
200
|
+
console.log(`No tracks found for ISRC ${isrc}.`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
console.log(`\nTracks matching ISRC ${isrc}:\n`);
|
|
204
|
+
for (const t of tracks) {
|
|
205
|
+
const artistStr = t.artists.length > 0 ? ` by ${t.artists.join(', ')}` : '';
|
|
206
|
+
const extras = [t.duration, t.popularity !== undefined ? `popularity: ${t.popularity}` : undefined]
|
|
207
|
+
.filter(Boolean)
|
|
208
|
+
.join(', ');
|
|
209
|
+
console.log(` [${t.id}] ${t.title}${artistStr}${extras ? ` (${extras})` : ''}`);
|
|
210
|
+
}
|
|
211
|
+
console.log();
|
|
179
212
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const extras = [t.duration, t.popularity !== undefined ? `popularity: ${t.popularity}` : undefined]
|
|
184
|
-
.filter(Boolean)
|
|
185
|
-
.join(', ');
|
|
186
|
-
console.log(` [${t.id}] ${t.title}${artistStr}${extras ? ` (${extras})` : ''}`);
|
|
213
|
+
catch (err) {
|
|
214
|
+
console.error(`Error: ${err.message}`);
|
|
215
|
+
process.exit(1);
|
|
187
216
|
}
|
|
188
|
-
console.log();
|
|
189
217
|
}
|
|
190
|
-
async function
|
|
191
|
-
const client = await (0, auth_1.getApiClient)();
|
|
218
|
+
async function getSimilarTracksData(trackId, client, countryCode) {
|
|
192
219
|
const { data, error } = await client.GET('/tracks/{id}/relationships/similarTracks', {
|
|
193
220
|
params: {
|
|
194
221
|
path: { id: trackId },
|
|
195
222
|
query: {
|
|
196
|
-
countryCode
|
|
223
|
+
countryCode,
|
|
197
224
|
include: ['similarTracks'],
|
|
198
225
|
},
|
|
199
226
|
},
|
|
200
227
|
});
|
|
201
228
|
if (error || !data) {
|
|
202
|
-
|
|
203
|
-
process.exit(1);
|
|
229
|
+
throw new Error(`Failed to get similar tracks — ${JSON.stringify(error)}`);
|
|
204
230
|
}
|
|
205
231
|
const included = data.included ?? [];
|
|
206
|
-
|
|
232
|
+
return included
|
|
207
233
|
.filter((item) => item.type === 'tracks')
|
|
208
234
|
.map((item) => {
|
|
209
235
|
const attrs = item.attributes;
|
|
@@ -215,21 +241,32 @@ async function getSimilarTracks(trackId, json) {
|
|
|
215
241
|
popularity: attrs?.popularity,
|
|
216
242
|
};
|
|
217
243
|
});
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
244
|
+
}
|
|
245
|
+
async function getSimilarTracks(trackId, json) {
|
|
246
|
+
const client = await (0, auth_1.getApiClient)();
|
|
247
|
+
const countryCode = await (0, auth_1.getCountryCode)();
|
|
248
|
+
try {
|
|
249
|
+
const tracks = await getSimilarTracksData(trackId, client, countryCode);
|
|
250
|
+
if (json) {
|
|
251
|
+
console.log(JSON.stringify(tracks, null, 2));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (tracks.length === 0) {
|
|
255
|
+
console.log(`No similar tracks found for track ${trackId}.`);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
console.log(`\nSimilar tracks to ${trackId}:\n`);
|
|
259
|
+
for (const t of tracks) {
|
|
260
|
+
const extras = [t.duration, t.popularity !== undefined ? `popularity: ${t.popularity}` : undefined]
|
|
261
|
+
.filter(Boolean)
|
|
262
|
+
.join(', ');
|
|
263
|
+
console.log(` [${t.id}] ${t.title}${extras ? ` (${extras})` : ''}`);
|
|
264
|
+
}
|
|
265
|
+
console.log();
|
|
225
266
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
.filter(Boolean)
|
|
230
|
-
.join(', ');
|
|
231
|
-
console.log(` [${t.id}] ${t.title}${extras ? ` (${extras})` : ''}`);
|
|
267
|
+
catch (err) {
|
|
268
|
+
console.error(`Error: ${err.message}`);
|
|
269
|
+
process.exit(1);
|
|
232
270
|
}
|
|
233
|
-
console.log();
|
|
234
271
|
}
|
|
235
272
|
//# sourceMappingURL=track.js.map
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
export type SearchType = 'artist' | 'album' | 'track' | 'video' | 'playlist';
|
|
2
|
+
export interface SearchResult {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
name: string;
|
|
6
|
+
extra?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface SearchSuggestionsResult {
|
|
9
|
+
suggestions: string[];
|
|
10
|
+
directHits: Array<{
|
|
11
|
+
id: string;
|
|
12
|
+
type: string;
|
|
13
|
+
name: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export interface ArtistInfo {
|
|
17
|
+
id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
popularity?: number;
|
|
20
|
+
handle?: string;
|
|
21
|
+
biography?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface ArtistTrack {
|
|
24
|
+
id: string;
|
|
25
|
+
title: string;
|
|
26
|
+
duration: string;
|
|
27
|
+
isrc?: string;
|
|
28
|
+
popularity?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface ArtistAlbum {
|
|
31
|
+
id: string;
|
|
32
|
+
title: string;
|
|
33
|
+
albumType?: string;
|
|
34
|
+
releaseDate?: string;
|
|
35
|
+
numberOfItems?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface SimilarArtist {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
popularity?: number;
|
|
41
|
+
}
|
|
42
|
+
export interface RadioPlaylist {
|
|
43
|
+
id: string;
|
|
44
|
+
type?: string;
|
|
45
|
+
name: string;
|
|
46
|
+
numberOfItems?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface TrackInfo {
|
|
49
|
+
id: string;
|
|
50
|
+
title: string;
|
|
51
|
+
artists: string[];
|
|
52
|
+
album?: string;
|
|
53
|
+
duration: string;
|
|
54
|
+
isrc?: string;
|
|
55
|
+
bpm?: number;
|
|
56
|
+
key?: string;
|
|
57
|
+
popularity?: number;
|
|
58
|
+
explicit?: boolean;
|
|
59
|
+
coverUrl?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface SimilarTrack {
|
|
62
|
+
id: string;
|
|
63
|
+
title: string;
|
|
64
|
+
duration: string;
|
|
65
|
+
isrc?: string;
|
|
66
|
+
popularity?: number;
|
|
67
|
+
}
|
|
68
|
+
export interface AlbumInfo {
|
|
69
|
+
id: string;
|
|
70
|
+
title: string;
|
|
71
|
+
artists: string[];
|
|
72
|
+
albumType?: string;
|
|
73
|
+
releaseDate?: string;
|
|
74
|
+
numberOfItems?: number;
|
|
75
|
+
duration: string;
|
|
76
|
+
popularity?: number;
|
|
77
|
+
explicit?: boolean;
|
|
78
|
+
barcodeId?: string;
|
|
79
|
+
coverUrl?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface AlbumResult {
|
|
82
|
+
id: string;
|
|
83
|
+
title: string;
|
|
84
|
+
albumType?: string;
|
|
85
|
+
releaseDate?: string;
|
|
86
|
+
numberOfItems?: number;
|
|
87
|
+
duration: string;
|
|
88
|
+
barcodeId?: string;
|
|
89
|
+
}
|
|
90
|
+
export interface PlaylistInfo {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
description?: string;
|
|
94
|
+
numberOfItems?: number;
|
|
95
|
+
createdAt?: string;
|
|
96
|
+
lastModifiedAt?: string;
|
|
97
|
+
}
|
|
98
|
+
export interface PlaybackInfo {
|
|
99
|
+
trackId: string;
|
|
100
|
+
presentation?: string;
|
|
101
|
+
previewReason?: string;
|
|
102
|
+
audioQuality?: string;
|
|
103
|
+
formats?: string[];
|
|
104
|
+
manifestMimeType?: string;
|
|
105
|
+
trackReplayGain?: number;
|
|
106
|
+
trackPeakAmplitude?: number;
|
|
107
|
+
albumReplayGain?: number;
|
|
108
|
+
albumPeakAmplitude?: number;
|
|
109
|
+
}
|
|
110
|
+
export interface PlaybackUrl {
|
|
111
|
+
trackId: string;
|
|
112
|
+
audioQuality?: string;
|
|
113
|
+
url?: string;
|
|
114
|
+
type?: 'direct' | 'dash';
|
|
115
|
+
initUrl?: string;
|
|
116
|
+
segmentCount?: number;
|
|
117
|
+
}
|
|
118
|
+
export interface UserProfile {
|
|
119
|
+
id: string;
|
|
120
|
+
username: string;
|
|
121
|
+
country: string;
|
|
122
|
+
email?: string;
|
|
123
|
+
}
|
|
124
|
+
export type MixCategory = 'daily' | 'discovery' | 'new-release' | 'offline';
|
|
125
|
+
export interface RecommendationItem {
|
|
126
|
+
id: string;
|
|
127
|
+
type: string;
|
|
128
|
+
name: string;
|
|
129
|
+
category?: MixCategory;
|
|
130
|
+
}
|
|
131
|
+
export interface MixItem {
|
|
132
|
+
id: string;
|
|
133
|
+
type: string;
|
|
134
|
+
name: string;
|
|
135
|
+
}
|
|
136
|
+
export interface RecentItem {
|
|
137
|
+
id: string;
|
|
138
|
+
name: string;
|
|
139
|
+
addedAt?: string;
|
|
140
|
+
}
|
|
141
|
+
export interface SearchHistoryEntry {
|
|
142
|
+
id: string;
|
|
143
|
+
query: string;
|
|
144
|
+
}
|
|
145
|
+
export type SavedItemType = 'tracks' | 'albums' | 'artists' | 'playlists' | 'videos';
|
|
146
|
+
export interface SavedItem {
|
|
147
|
+
id: string;
|
|
148
|
+
type: string;
|
|
149
|
+
name: string;
|
|
150
|
+
}
|
|
151
|
+
export interface ShareLink {
|
|
152
|
+
id: string;
|
|
153
|
+
code: string;
|
|
154
|
+
createdAt?: string;
|
|
155
|
+
url?: string;
|
|
156
|
+
}
|
|
157
|
+
export type LibraryResourceType = 'artist' | 'album' | 'track' | 'video';
|
|
158
|
+
export type RecentType = 'tracks' | 'albums' | 'artists';
|
package/dist/types.js
ADDED
package/dist/user.d.ts
CHANGED
package/dist/user.js
CHANGED
|
@@ -1,36 +1,45 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getUserProfileData = getUserProfileData;
|
|
3
4
|
exports.getUserProfile = getUserProfile;
|
|
4
5
|
const auth_1 = require("./auth");
|
|
5
|
-
async function
|
|
6
|
-
const client = await (0, auth_1.getApiClient)();
|
|
6
|
+
async function getUserProfileData(client) {
|
|
7
7
|
const { data, error } = await client.GET('/users/me', {
|
|
8
8
|
params: {},
|
|
9
9
|
});
|
|
10
10
|
if (error || !data) {
|
|
11
|
-
|
|
12
|
-
process.exit(1);
|
|
11
|
+
throw new Error(`Failed to get user profile — ${JSON.stringify(error)}`);
|
|
13
12
|
}
|
|
14
13
|
const attrs = data.data?.attributes ?? {};
|
|
15
|
-
|
|
14
|
+
return {
|
|
16
15
|
id: data.data?.id,
|
|
17
16
|
username: attrs.username,
|
|
18
17
|
country: attrs.country,
|
|
19
18
|
email: attrs.email,
|
|
20
19
|
};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
}
|
|
21
|
+
async function getUserProfile(json) {
|
|
22
|
+
const client = await (0, auth_1.getApiClient)();
|
|
23
|
+
try {
|
|
24
|
+
const result = await getUserProfileData(client);
|
|
25
|
+
if (json) {
|
|
26
|
+
console.log(JSON.stringify(result, null, 2));
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
console.log('\nUser profile:');
|
|
30
|
+
if (result.id)
|
|
31
|
+
console.log(` ID: ${result.id}`);
|
|
32
|
+
if (result.username)
|
|
33
|
+
console.log(` Username: ${result.username}`);
|
|
34
|
+
if (result.country)
|
|
35
|
+
console.log(` Country: ${result.country}`);
|
|
36
|
+
if (result.email)
|
|
37
|
+
console.log(` Email: ${result.email}`);
|
|
38
|
+
console.log();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.error(`Error: ${err.message}`);
|
|
42
|
+
process.exit(1);
|
|
24
43
|
}
|
|
25
|
-
console.log('\nUser profile:');
|
|
26
|
-
if (result.id)
|
|
27
|
-
console.log(` ID: ${result.id}`);
|
|
28
|
-
if (result.username)
|
|
29
|
-
console.log(` Username: ${result.username}`);
|
|
30
|
-
if (result.country)
|
|
31
|
-
console.log(` Country: ${result.country}`);
|
|
32
|
-
if (result.email)
|
|
33
|
-
console.log(` Email: ${result.email}`);
|
|
34
|
-
console.log();
|
|
35
44
|
}
|
|
36
45
|
//# sourceMappingURL=user.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucaperret/tidal-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "CLI for Tidal music streaming service, designed for LLM agent automation",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -51,13 +51,15 @@
|
|
|
51
51
|
"LICENSE"
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@tidal-music/api": "^0.
|
|
55
|
-
"@tidal-music/auth": "^1.
|
|
54
|
+
"@tidal-music/api": "^0.22.0",
|
|
55
|
+
"@tidal-music/auth": "^1.6.0",
|
|
56
56
|
"commander": "^14.0.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@
|
|
60
|
-
"
|
|
61
|
-
"
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
60
|
+
"@types/node": "^25.6.0",
|
|
61
|
+
"typescript": "^6.0.3",
|
|
62
|
+
"vitest": "^4.1.5",
|
|
63
|
+
"zod": "^4.4.3"
|
|
62
64
|
}
|
|
63
65
|
}
|