soundcloud-api-ts 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1742 @@
1
+ 'use strict';
2
+
3
+ var chunkNBKG62HR_js = require('./chunk-NBKG62HR.js');
4
+
5
+ // src/client/http.ts
6
+ var BASE_URL = "https://api.soundcloud.com";
7
+ var DEFAULT_RETRY = { maxRetries: 3, retryBaseDelay: 1e3 };
8
+ function delay(ms) {
9
+ return new Promise((resolve) => setTimeout(resolve, ms));
10
+ }
11
+ function isRetryable(status) {
12
+ return status === 429 || status >= 500 && status <= 599;
13
+ }
14
+ function getRetryDelay(response, attempt, config) {
15
+ if (response.status === 429) {
16
+ const retryAfter = response.headers.get("retry-after");
17
+ if (retryAfter) {
18
+ const seconds = Number(retryAfter);
19
+ if (!Number.isNaN(seconds)) return seconds * 1e3;
20
+ }
21
+ }
22
+ const base = config.retryBaseDelay * Math.pow(2, attempt);
23
+ return base + Math.random() * base * 0.1;
24
+ }
25
+ async function parseErrorBody(response) {
26
+ try {
27
+ return await response.json();
28
+ } catch {
29
+ return void 0;
30
+ }
31
+ }
32
+ async function scFetch(options, refreshCtx) {
33
+ const retryConfig = refreshCtx?.retry ?? DEFAULT_RETRY;
34
+ const execute = async (tokenOverride) => {
35
+ const url = `${BASE_URL}${options.path}`;
36
+ const headers = {
37
+ Accept: "application/json"
38
+ };
39
+ const token = tokenOverride ?? options.token;
40
+ if (token) {
41
+ headers["Authorization"] = `OAuth ${token}`;
42
+ }
43
+ let fetchBody;
44
+ if (options.body) {
45
+ if (options.body instanceof URLSearchParams) {
46
+ fetchBody = options.body;
47
+ headers["Content-Type"] = "application/x-www-form-urlencoded";
48
+ } else if (options.body instanceof FormData) {
49
+ fetchBody = options.body;
50
+ } else {
51
+ headers["Content-Type"] = options.contentType ?? "application/json";
52
+ fetchBody = JSON.stringify(options.body);
53
+ }
54
+ } else if (options.contentType) {
55
+ headers["Content-Type"] = options.contentType;
56
+ }
57
+ let lastResponse;
58
+ for (let attempt = 0; attempt <= retryConfig.maxRetries; attempt++) {
59
+ const response = await fetch(url, {
60
+ method: options.method,
61
+ headers,
62
+ body: fetchBody,
63
+ redirect: "manual"
64
+ });
65
+ if (response.status === 302) {
66
+ const location = response.headers.get("location");
67
+ if (location) return location;
68
+ }
69
+ if (response.status === 204 || response.headers.get("content-length") === "0") {
70
+ return void 0;
71
+ }
72
+ if (response.ok) {
73
+ return response.json();
74
+ }
75
+ if (!isRetryable(response.status)) {
76
+ const body2 = await parseErrorBody(response);
77
+ throw new chunkNBKG62HR_js.SoundCloudError(response.status, response.statusText, body2);
78
+ }
79
+ lastResponse = response;
80
+ if (attempt < retryConfig.maxRetries) {
81
+ const delayMs = getRetryDelay(response, attempt, retryConfig);
82
+ retryConfig.onDebug?.(
83
+ `Retry ${attempt + 1}/${retryConfig.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
84
+ );
85
+ await delay(delayMs);
86
+ }
87
+ }
88
+ const body = await parseErrorBody(lastResponse);
89
+ throw new chunkNBKG62HR_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
90
+ };
91
+ try {
92
+ return await execute();
93
+ } catch (err) {
94
+ if (refreshCtx?.onTokenRefresh && err instanceof chunkNBKG62HR_js.SoundCloudError && err.status === 401) {
95
+ const newToken = await refreshCtx.onTokenRefresh();
96
+ refreshCtx.setToken(newToken.access_token, newToken.refresh_token);
97
+ return execute(newToken.access_token);
98
+ }
99
+ throw err;
100
+ }
101
+ }
102
+ async function scFetchUrl(url, token, retryConfig) {
103
+ const config = retryConfig ?? DEFAULT_RETRY;
104
+ const headers = { Accept: "application/json" };
105
+ if (token) headers["Authorization"] = `OAuth ${token}`;
106
+ let lastResponse;
107
+ for (let attempt = 0; attempt <= config.maxRetries; attempt++) {
108
+ const response = await fetch(url, { method: "GET", headers, redirect: "manual" });
109
+ if (response.status === 302) {
110
+ const location = response.headers.get("location");
111
+ if (location) return location;
112
+ }
113
+ if (response.status === 204 || response.headers.get("content-length") === "0") {
114
+ return void 0;
115
+ }
116
+ if (response.ok) {
117
+ return response.json();
118
+ }
119
+ if (!isRetryable(response.status)) {
120
+ const body2 = await parseErrorBody(response);
121
+ throw new chunkNBKG62HR_js.SoundCloudError(response.status, response.statusText, body2);
122
+ }
123
+ lastResponse = response;
124
+ if (attempt < config.maxRetries) {
125
+ const delayMs = getRetryDelay(response, attempt, config);
126
+ config.onDebug?.(
127
+ `Retry ${attempt + 1}/${config.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
128
+ );
129
+ await delay(delayMs);
130
+ }
131
+ }
132
+ const body = await parseErrorBody(lastResponse);
133
+ throw new chunkNBKG62HR_js.SoundCloudError(lastResponse.status, lastResponse.statusText, body);
134
+ }
135
+
136
+ // src/client/paginate.ts
137
+ async function* paginate(firstPage, fetchNext) {
138
+ let page = await firstPage();
139
+ yield page.collection;
140
+ while (page.next_href) {
141
+ page = await fetchNext(page.next_href);
142
+ yield page.collection;
143
+ }
144
+ }
145
+ async function* paginateItems(firstPage, fetchNext) {
146
+ for await (const page of paginate(firstPage, fetchNext)) {
147
+ for (const item of page) {
148
+ yield item;
149
+ }
150
+ }
151
+ }
152
+ async function fetchAll(firstPage, fetchNext, options) {
153
+ const result = [];
154
+ const max = options?.maxItems ?? Infinity;
155
+ for await (const page of paginate(firstPage, fetchNext)) {
156
+ for (const item of page) {
157
+ result.push(item);
158
+ if (result.length >= max) return result;
159
+ }
160
+ }
161
+ return result;
162
+ }
163
+
164
+ // src/client/SoundCloudClient.ts
165
+ function resolveToken(tokenGetter, explicit) {
166
+ const t = explicit ?? tokenGetter();
167
+ if (!t) throw new Error("No access token available. Call client.setToken() or pass a token explicitly.");
168
+ return t;
169
+ }
170
+ exports.SoundCloudClient = class _SoundCloudClient {
171
+ config;
172
+ _accessToken;
173
+ _refreshToken;
174
+ /** Authentication methods (OAuth token grants, sign out) */
175
+ auth;
176
+ /** Authenticated user endpoints (/me) */
177
+ me;
178
+ /** User profile endpoints (/users) */
179
+ users;
180
+ /** Track endpoints (/tracks) */
181
+ tracks;
182
+ /** Playlist endpoints (/playlists) */
183
+ playlists;
184
+ /** Search endpoints */
185
+ search;
186
+ /** URL resolution endpoint (/resolve) */
187
+ resolve;
188
+ /** Like/unlike actions (/likes) */
189
+ likes;
190
+ /** Repost/unrepost actions (/reposts) */
191
+ reposts;
192
+ /**
193
+ * Creates a new SoundCloudClient instance.
194
+ *
195
+ * @param config - Client configuration including OAuth credentials and optional settings
196
+ */
197
+ constructor(config) {
198
+ this.config = config;
199
+ const getToken = () => this._accessToken;
200
+ const retryConfig = {
201
+ maxRetries: config.maxRetries ?? 3,
202
+ retryBaseDelay: config.retryBaseDelay ?? 1e3,
203
+ onDebug: config.onDebug
204
+ };
205
+ const refreshCtx = config.onTokenRefresh ? {
206
+ getToken,
207
+ onTokenRefresh: async () => {
208
+ const result = await config.onTokenRefresh(this);
209
+ return result;
210
+ },
211
+ setToken: (a, r) => this.setToken(a, r),
212
+ retry: retryConfig
213
+ } : {
214
+ getToken,
215
+ setToken: (a, r) => this.setToken(a, r),
216
+ retry: retryConfig
217
+ };
218
+ this.auth = new _SoundCloudClient.Auth(this.config);
219
+ this.me = new _SoundCloudClient.Me(getToken, refreshCtx);
220
+ this.users = new _SoundCloudClient.Users(getToken, refreshCtx);
221
+ this.tracks = new _SoundCloudClient.Tracks(getToken, refreshCtx);
222
+ this.playlists = new _SoundCloudClient.Playlists(getToken, refreshCtx);
223
+ this.search = new _SoundCloudClient.Search(getToken, refreshCtx);
224
+ this.resolve = new _SoundCloudClient.Resolve(getToken, refreshCtx);
225
+ this.likes = new _SoundCloudClient.Likes(getToken, refreshCtx);
226
+ this.reposts = new _SoundCloudClient.Reposts(getToken, refreshCtx);
227
+ }
228
+ /**
229
+ * Store an access token (and optionally refresh token) on this client instance.
230
+ *
231
+ * @param accessToken - The OAuth access token to store
232
+ * @param refreshToken - Optional refresh token for automatic token renewal
233
+ */
234
+ setToken(accessToken, refreshToken) {
235
+ this._accessToken = accessToken;
236
+ if (refreshToken !== void 0) this._refreshToken = refreshToken;
237
+ }
238
+ /** Clear all stored tokens from this client instance. */
239
+ clearToken() {
240
+ this._accessToken = void 0;
241
+ this._refreshToken = void 0;
242
+ }
243
+ /** Get the currently stored access token, or `undefined` if none is set. */
244
+ get accessToken() {
245
+ return this._accessToken;
246
+ }
247
+ /** Get the currently stored refresh token, or `undefined` if none is set. */
248
+ get refreshToken() {
249
+ return this._refreshToken;
250
+ }
251
+ /**
252
+ * Async generator that follows `next_href` automatically, yielding each page's `collection`.
253
+ *
254
+ * @param firstPage - Function that fetches the first page
255
+ * @returns An async generator yielding arrays of items (one per page)
256
+ *
257
+ * @example
258
+ * ```ts
259
+ * for await (const page of sc.paginate(() => sc.search.tracks('lofi'))) {
260
+ * console.log(page); // SoundCloudTrack[]
261
+ * }
262
+ * ```
263
+ */
264
+ paginate(firstPage) {
265
+ const token = this._accessToken;
266
+ return paginate(firstPage, (url) => scFetchUrl(url, token));
267
+ }
268
+ /**
269
+ * Async generator that yields individual items across all pages.
270
+ *
271
+ * @param firstPage - Function that fetches the first page
272
+ * @returns An async generator yielding individual items
273
+ *
274
+ * @example
275
+ * ```ts
276
+ * for await (const track of sc.paginateItems(() => sc.search.tracks('lofi'))) {
277
+ * console.log(track.title); // single SoundCloudTrack
278
+ * }
279
+ * ```
280
+ */
281
+ paginateItems(firstPage) {
282
+ const token = this._accessToken;
283
+ return paginateItems(firstPage, (url) => scFetchUrl(url, token));
284
+ }
285
+ /**
286
+ * Collects all pages into a single flat array.
287
+ *
288
+ * @param firstPage - Function that fetches the first page
289
+ * @param options - Optional configuration
290
+ * @param options.maxItems - Maximum number of items to collect
291
+ * @returns A promise resolving to a flat array of all items
292
+ *
293
+ * @example
294
+ * ```ts
295
+ * const allTracks = await sc.fetchAll(() => sc.search.tracks('lofi'), { maxItems: 100 });
296
+ * console.log(allTracks.length);
297
+ * ```
298
+ */
299
+ fetchAll(firstPage, options) {
300
+ const token = this._accessToken;
301
+ return fetchAll(firstPage, (url) => scFetchUrl(url, token), options);
302
+ }
303
+ };
304
+ ((SoundCloudClient2) => {
305
+ class Auth {
306
+ constructor(config) {
307
+ this.config = config;
308
+ }
309
+ /**
310
+ * Build the authorization URL to redirect users to SoundCloud's OAuth login page.
311
+ *
312
+ * @param options - Optional parameters for the authorization request
313
+ * @param options.state - Opaque state value for CSRF protection
314
+ * @param options.codeChallenge - PKCE S256 code challenge for enhanced security
315
+ * @returns The full authorization URL to redirect the user to
316
+ * @throws {Error} If `redirectUri` was not provided in the client config
317
+ *
318
+ * @example
319
+ * ```ts
320
+ * const url = sc.auth.getAuthorizationUrl({ state: 'random-state' });
321
+ * // Redirect user to `url`
322
+ * ```
323
+ *
324
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2
325
+ */
326
+ getAuthorizationUrl(options) {
327
+ if (!this.config.redirectUri) throw new Error("redirectUri is required for getAuthorizationUrl");
328
+ const params = new URLSearchParams({
329
+ client_id: this.config.clientId,
330
+ redirect_uri: this.config.redirectUri,
331
+ response_type: "code"
332
+ });
333
+ if (options?.state) params.set("state", options.state);
334
+ if (options?.codeChallenge) {
335
+ params.set("code_challenge", options.codeChallenge);
336
+ params.set("code_challenge_method", "S256");
337
+ }
338
+ return `https://api.soundcloud.com/connect?${params}`;
339
+ }
340
+ /**
341
+ * Exchange client credentials for an access token (machine-to-machine auth).
342
+ *
343
+ * @returns The OAuth token response
344
+ * @throws {SoundCloudError} When authentication fails
345
+ *
346
+ * @example
347
+ * ```ts
348
+ * const token = await sc.auth.getClientToken();
349
+ * sc.setToken(token.access_token);
350
+ * ```
351
+ *
352
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
353
+ */
354
+ async getClientToken() {
355
+ return scFetch({
356
+ path: "/oauth2/token",
357
+ method: "POST",
358
+ body: new URLSearchParams({
359
+ grant_type: "client_credentials",
360
+ client_id: this.config.clientId,
361
+ client_secret: this.config.clientSecret
362
+ })
363
+ });
364
+ }
365
+ /**
366
+ * Exchange an authorization code for user tokens (authorization_code grant).
367
+ *
368
+ * @param code - The authorization code received from the OAuth callback
369
+ * @param codeVerifier - PKCE code verifier if a code challenge was used
370
+ * @returns The OAuth token response including access and refresh tokens
371
+ * @throws {SoundCloudError} When the code is invalid or expired
372
+ *
373
+ * @example
374
+ * ```ts
375
+ * const token = await sc.auth.getUserToken(code, codeVerifier);
376
+ * sc.setToken(token.access_token, token.refresh_token);
377
+ * ```
378
+ *
379
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
380
+ */
381
+ async getUserToken(code, codeVerifier) {
382
+ const params = {
383
+ grant_type: "authorization_code",
384
+ client_id: this.config.clientId,
385
+ client_secret: this.config.clientSecret,
386
+ redirect_uri: this.config.redirectUri,
387
+ code
388
+ };
389
+ if (codeVerifier) params.code_verifier = codeVerifier;
390
+ return scFetch({
391
+ path: "/oauth2/token",
392
+ method: "POST",
393
+ body: new URLSearchParams(params)
394
+ });
395
+ }
396
+ /**
397
+ * Refresh an expired access token using a refresh token.
398
+ *
399
+ * @param refreshToken - The refresh token from a previous token response
400
+ * @returns A new OAuth token response with fresh access and refresh tokens
401
+ * @throws {SoundCloudError} When the refresh token is invalid or expired
402
+ *
403
+ * @example
404
+ * ```ts
405
+ * const newToken = await sc.auth.refreshUserToken(sc.refreshToken!);
406
+ * sc.setToken(newToken.access_token, newToken.refresh_token);
407
+ * ```
408
+ *
409
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/oauth2/post_oauth2_token
410
+ */
411
+ async refreshUserToken(refreshToken) {
412
+ return scFetch({
413
+ path: "/oauth2/token",
414
+ method: "POST",
415
+ body: new URLSearchParams({
416
+ grant_type: "refresh_token",
417
+ client_id: this.config.clientId,
418
+ client_secret: this.config.clientSecret,
419
+ redirect_uri: this.config.redirectUri,
420
+ refresh_token: refreshToken
421
+ })
422
+ });
423
+ }
424
+ /**
425
+ * Invalidate the session associated with an access token.
426
+ *
427
+ * **Note:** This hits `https://secure.soundcloud.com`, NOT the regular
428
+ * `api.soundcloud.com` host used by all other endpoints.
429
+ *
430
+ * @param accessToken - The access token to invalidate
431
+ * @throws {Error} When the sign-out request fails
432
+ *
433
+ * @example
434
+ * ```ts
435
+ * await sc.auth.signOut(sc.accessToken!);
436
+ * sc.clearToken();
437
+ * ```
438
+ */
439
+ async signOut(accessToken) {
440
+ const res = await fetch("https://secure.soundcloud.com/sign-out", {
441
+ method: "POST",
442
+ headers: { "Content-Type": "application/json" },
443
+ body: JSON.stringify({ access_token: accessToken })
444
+ });
445
+ if (!res.ok) throw new Error(`Sign-out failed: ${res.status}`);
446
+ }
447
+ }
448
+ SoundCloudClient2.Auth = Auth;
449
+ class Me {
450
+ constructor(getToken, refreshCtx) {
451
+ this.getToken = getToken;
452
+ this.refreshCtx = refreshCtx;
453
+ }
454
+ fetch(opts) {
455
+ return scFetch(opts, this.refreshCtx);
456
+ }
457
+ /**
458
+ * Get the authenticated user's profile.
459
+ *
460
+ * @param options - Optional token override
461
+ * @returns The authenticated user's full profile
462
+ * @throws {SoundCloudError} When the API returns an error
463
+ *
464
+ * @example
465
+ * ```ts
466
+ * const me = await sc.me.getMe();
467
+ * console.log(me.username, me.followers_count);
468
+ * ```
469
+ *
470
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me
471
+ */
472
+ async getMe(options) {
473
+ const t = resolveToken(this.getToken, options?.token);
474
+ return this.fetch({ path: "/me", method: "GET", token: t });
475
+ }
476
+ /**
477
+ * Get the authenticated user's activity feed.
478
+ *
479
+ * @param limit - Maximum number of activities per page
480
+ * @param options - Optional token override
481
+ * @returns Paginated activities response with `future_href` for polling
482
+ * @throws {SoundCloudError} When the API returns an error
483
+ *
484
+ * @example
485
+ * ```ts
486
+ * const activities = await sc.me.getActivities(25);
487
+ * activities.collection.forEach(a => console.log(a.type, a.created_at));
488
+ * ```
489
+ *
490
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_activities
491
+ */
492
+ async getActivities(limit, options) {
493
+ const t = resolveToken(this.getToken, options?.token);
494
+ return this.fetch({ path: `/me/activities?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
495
+ }
496
+ /**
497
+ * Get the authenticated user's own activities (uploads, reposts).
498
+ *
499
+ * @param limit - Maximum number of activities per page
500
+ * @param options - Optional token override
501
+ * @returns Paginated activities response
502
+ * @throws {SoundCloudError} When the API returns an error
503
+ *
504
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_activities_all_own
505
+ */
506
+ async getActivitiesOwn(limit, options) {
507
+ const t = resolveToken(this.getToken, options?.token);
508
+ return this.fetch({ path: `/me/activities/all/own?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
509
+ }
510
+ /**
511
+ * Get track-related activities in the authenticated user's feed.
512
+ *
513
+ * @param limit - Maximum number of activities per page
514
+ * @param options - Optional token override
515
+ * @returns Paginated activities response filtered to track activities
516
+ * @throws {SoundCloudError} When the API returns an error
517
+ *
518
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_activities_tracks
519
+ */
520
+ async getActivitiesTracks(limit, options) {
521
+ const t = resolveToken(this.getToken, options?.token);
522
+ return this.fetch({ path: `/me/activities/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
523
+ }
524
+ /**
525
+ * Get tracks liked by the authenticated user.
526
+ *
527
+ * @param limit - Maximum number of tracks per page
528
+ * @param options - Optional token override
529
+ * @returns Paginated list of liked tracks
530
+ * @throws {SoundCloudError} When the API returns an error
531
+ *
532
+ * @example
533
+ * ```ts
534
+ * const likes = await sc.me.getLikesTracks(50);
535
+ * likes.collection.forEach(t => console.log(t.title));
536
+ * ```
537
+ *
538
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_likes_tracks
539
+ */
540
+ async getLikesTracks(limit, options) {
541
+ const t = resolveToken(this.getToken, options?.token);
542
+ return this.fetch({ path: `/me/likes/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
543
+ }
544
+ /**
545
+ * Get playlists liked by the authenticated user.
546
+ *
547
+ * @param limit - Maximum number of playlists per page
548
+ * @param options - Optional token override
549
+ * @returns Paginated list of liked playlists
550
+ * @throws {SoundCloudError} When the API returns an error
551
+ *
552
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_likes_playlists
553
+ */
554
+ async getLikesPlaylists(limit, options) {
555
+ const t = resolveToken(this.getToken, options?.token);
556
+ return this.fetch({ path: `/me/likes/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
557
+ }
558
+ /**
559
+ * Get users the authenticated user is following.
560
+ *
561
+ * @param limit - Maximum number of users per page
562
+ * @param options - Optional token override
563
+ * @returns Paginated list of followed users
564
+ * @throws {SoundCloudError} When the API returns an error
565
+ *
566
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_followings
567
+ */
568
+ async getFollowings(limit, options) {
569
+ const t = resolveToken(this.getToken, options?.token);
570
+ return this.fetch({ path: `/me/followings?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
571
+ }
572
+ /**
573
+ * Get recent tracks from users the authenticated user is following.
574
+ *
575
+ * @param limit - Maximum number of tracks per page
576
+ * @param options - Optional token override
577
+ * @returns Paginated list of tracks from followed users
578
+ * @throws {SoundCloudError} When the API returns an error
579
+ *
580
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_followings_tracks
581
+ */
582
+ async getFollowingsTracks(limit, options) {
583
+ const t = resolveToken(this.getToken, options?.token);
584
+ return this.fetch({ path: `/me/followings/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
585
+ }
586
+ /**
587
+ * Follow a user.
588
+ *
589
+ * @param userUrn - The user's ID or URN to follow
590
+ * @param options - Optional token override
591
+ * @throws {SoundCloudError} When the API returns an error
592
+ *
593
+ * @example
594
+ * ```ts
595
+ * await sc.me.follow(123456);
596
+ * ```
597
+ *
598
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/put_me_followings__user_id_
599
+ */
600
+ async follow(userUrn, options) {
601
+ const t = resolveToken(this.getToken, options?.token);
602
+ return this.fetch({ path: `/me/followings/${userUrn}`, method: "PUT", token: t });
603
+ }
604
+ /**
605
+ * Unfollow a user.
606
+ *
607
+ * @param userUrn - The user's ID or URN to unfollow
608
+ * @param options - Optional token override
609
+ * @throws {SoundCloudError} When the API returns an error
610
+ *
611
+ * @example
612
+ * ```ts
613
+ * await sc.me.unfollow(123456);
614
+ * ```
615
+ *
616
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/delete_me_followings__user_id_
617
+ */
618
+ async unfollow(userUrn, options) {
619
+ const t = resolveToken(this.getToken, options?.token);
620
+ return this.fetch({ path: `/me/followings/${userUrn}`, method: "DELETE", token: t });
621
+ }
622
+ /**
623
+ * Get the authenticated user's followers.
624
+ *
625
+ * @param limit - Maximum number of users per page
626
+ * @param options - Optional token override
627
+ * @returns Paginated list of follower users
628
+ * @throws {SoundCloudError} When the API returns an error
629
+ *
630
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_followers
631
+ */
632
+ async getFollowers(limit, options) {
633
+ const t = resolveToken(this.getToken, options?.token);
634
+ return this.fetch({ path: `/me/followers?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
635
+ }
636
+ /**
637
+ * Get the authenticated user's playlists.
638
+ *
639
+ * @param limit - Maximum number of playlists per page
640
+ * @param options - Optional token override
641
+ * @returns Paginated list of playlists
642
+ * @throws {SoundCloudError} When the API returns an error
643
+ *
644
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_playlists
645
+ */
646
+ async getPlaylists(limit, options) {
647
+ const t = resolveToken(this.getToken, options?.token);
648
+ return this.fetch({ path: `/me/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
649
+ }
650
+ /**
651
+ * Get the authenticated user's tracks.
652
+ *
653
+ * @param limit - Maximum number of tracks per page
654
+ * @param options - Optional token override
655
+ * @returns Paginated list of tracks
656
+ * @throws {SoundCloudError} When the API returns an error
657
+ *
658
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/me/get_me_tracks
659
+ */
660
+ async getTracks(limit, options) {
661
+ const t = resolveToken(this.getToken, options?.token);
662
+ return this.fetch({ path: `/me/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
663
+ }
664
+ }
665
+ SoundCloudClient2.Me = Me;
666
+ class Users {
667
+ constructor(getToken, refreshCtx) {
668
+ this.getToken = getToken;
669
+ this.refreshCtx = refreshCtx;
670
+ }
671
+ fetch(opts) {
672
+ return scFetch(opts, this.refreshCtx);
673
+ }
674
+ /**
675
+ * Get a user's profile by ID.
676
+ *
677
+ * @param userId - The user's numeric ID or URN
678
+ * @param options - Optional token override
679
+ * @returns The user's public profile
680
+ * @throws {SoundCloudError} When the user is not found or the API returns an error
681
+ *
682
+ * @example
683
+ * ```ts
684
+ * const user = await sc.users.getUser(123456);
685
+ * console.log(user.username, user.followers_count);
686
+ * ```
687
+ *
688
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id_
689
+ */
690
+ async getUser(userId, options) {
691
+ const t = resolveToken(this.getToken, options?.token);
692
+ return this.fetch({ path: `/users/${userId}`, method: "GET", token: t });
693
+ }
694
+ /**
695
+ * Get a user's followers.
696
+ *
697
+ * @param userId - The user's numeric ID or URN
698
+ * @param limit - Maximum number of followers per page
699
+ * @param options - Optional token override
700
+ * @returns Paginated list of follower users
701
+ * @throws {SoundCloudError} When the API returns an error
702
+ *
703
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__followers
704
+ */
705
+ async getFollowers(userId, limit, options) {
706
+ const t = resolveToken(this.getToken, options?.token);
707
+ return this.fetch({ path: `/users/${userId}/followers?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
708
+ }
709
+ /**
710
+ * Get users that a user is following.
711
+ *
712
+ * @param userId - The user's numeric ID or URN
713
+ * @param limit - Maximum number of users per page
714
+ * @param options - Optional token override
715
+ * @returns Paginated list of followed users
716
+ * @throws {SoundCloudError} When the API returns an error
717
+ *
718
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__followings
719
+ */
720
+ async getFollowings(userId, limit, options) {
721
+ const t = resolveToken(this.getToken, options?.token);
722
+ return this.fetch({ path: `/users/${userId}/followings?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
723
+ }
724
+ /**
725
+ * Get a user's public tracks.
726
+ *
727
+ * @param userId - The user's numeric ID or URN
728
+ * @param limit - Maximum number of tracks per page
729
+ * @param options - Optional token override
730
+ * @returns Paginated list of tracks
731
+ * @throws {SoundCloudError} When the API returns an error
732
+ *
733
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__tracks
734
+ */
735
+ async getTracks(userId, limit, options) {
736
+ const t = resolveToken(this.getToken, options?.token);
737
+ return this.fetch({ path: `/users/${userId}/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
738
+ }
739
+ /**
740
+ * Get a user's public playlists.
741
+ *
742
+ * @param userId - The user's numeric ID or URN
743
+ * @param limit - Maximum number of playlists per page
744
+ * @param options - Optional token override
745
+ * @returns Paginated list of playlists (without full track data)
746
+ * @throws {SoundCloudError} When the API returns an error
747
+ *
748
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__playlists
749
+ */
750
+ async getPlaylists(userId, limit, options) {
751
+ const t = resolveToken(this.getToken, options?.token);
752
+ return this.fetch({ path: `/users/${userId}/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true&show_tracks=false`, method: "GET", token: t });
753
+ }
754
+ /**
755
+ * Get tracks liked by a user.
756
+ *
757
+ * @param userId - The user's numeric ID or URN
758
+ * @param limit - Maximum number of tracks per page
759
+ * @param cursor - Pagination cursor from a previous response's `next_href`
760
+ * @param options - Optional token override
761
+ * @returns Paginated list of liked tracks
762
+ * @throws {SoundCloudError} When the API returns an error
763
+ *
764
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__likes_tracks
765
+ */
766
+ async getLikesTracks(userId, limit, cursor, options) {
767
+ const t = resolveToken(this.getToken, options?.token);
768
+ return this.fetch({ path: `/users/${userId}/likes/tracks?${limit ? `limit=${limit}&` : ""}${cursor ? `cursor=${cursor}&` : ""}linked_partitioning=true`, method: "GET", token: t });
769
+ }
770
+ /**
771
+ * Get playlists liked by a user.
772
+ *
773
+ * @param userId - The user's numeric ID or URN
774
+ * @param limit - Maximum number of playlists per page
775
+ * @param options - Optional token override
776
+ * @returns Paginated list of liked playlists
777
+ * @throws {SoundCloudError} When the API returns an error
778
+ *
779
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__likes_playlists
780
+ */
781
+ async getLikesPlaylists(userId, limit, options) {
782
+ const t = resolveToken(this.getToken, options?.token);
783
+ return this.fetch({ path: `/users/${userId}/likes/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
784
+ }
785
+ /**
786
+ * Get a user's external web profile links (Twitter, Instagram, etc.).
787
+ *
788
+ * @param userId - The user's numeric ID or URN
789
+ * @param options - Optional token override
790
+ * @returns Array of web profile objects
791
+ * @throws {SoundCloudError} When the API returns an error
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * const profiles = await sc.users.getWebProfiles(123456);
796
+ * profiles.forEach(p => console.log(p.service, p.url));
797
+ * ```
798
+ *
799
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users__user_id__web_profiles
800
+ */
801
+ async getWebProfiles(userId, options) {
802
+ const t = resolveToken(this.getToken, options?.token);
803
+ return this.fetch({ path: `/users/${userId}/web-profiles`, method: "GET", token: t });
804
+ }
805
+ }
806
+ SoundCloudClient2.Users = Users;
807
+ class Tracks {
808
+ constructor(getToken, refreshCtx) {
809
+ this.getToken = getToken;
810
+ this.refreshCtx = refreshCtx;
811
+ }
812
+ fetch(opts) {
813
+ return scFetch(opts, this.refreshCtx);
814
+ }
815
+ /**
816
+ * Get a track by ID.
817
+ *
818
+ * @param trackId - The track's numeric ID or URN
819
+ * @param options - Optional token override
820
+ * @returns The track object with full metadata
821
+ * @throws {SoundCloudError} When the track is not found or the API returns an error
822
+ *
823
+ * @example
824
+ * ```ts
825
+ * const track = await sc.tracks.getTrack(123456);
826
+ * console.log(track.title, track.duration);
827
+ * ```
828
+ *
829
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id_
830
+ */
831
+ async getTrack(trackId, options) {
832
+ const t = resolveToken(this.getToken, options?.token);
833
+ return this.fetch({ path: `/tracks/${trackId}`, method: "GET", token: t });
834
+ }
835
+ /**
836
+ * Get stream URLs for a track.
837
+ *
838
+ * @param trackId - The track's numeric ID or URN
839
+ * @param options - Optional token override
840
+ * @returns Object containing available stream URLs (HLS, MP3, preview)
841
+ * @throws {SoundCloudError} When the track is not found or not streamable
842
+ *
843
+ * @example
844
+ * ```ts
845
+ * const streams = await sc.tracks.getStreams(123456);
846
+ * console.log(streams.hls_mp3_128_url);
847
+ * ```
848
+ *
849
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id__streams
850
+ */
851
+ async getStreams(trackId, options) {
852
+ const t = resolveToken(this.getToken, options?.token);
853
+ return this.fetch({ path: `/tracks/${trackId}/streams`, method: "GET", token: t });
854
+ }
855
+ /**
856
+ * Get comments on a track.
857
+ *
858
+ * @param trackId - The track's numeric ID or URN
859
+ * @param limit - Maximum number of comments per page
860
+ * @param options - Optional token override
861
+ * @returns Paginated list of comments
862
+ * @throws {SoundCloudError} When the API returns an error
863
+ *
864
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id__comments
865
+ */
866
+ async getComments(trackId, limit, options) {
867
+ const t = resolveToken(this.getToken, options?.token);
868
+ return this.fetch({ path: `/tracks/${trackId}/comments?threaded=1&filter_replies=0${limit ? `&limit=${limit}` : ""}&linked_partitioning=true`, method: "GET", token: t });
869
+ }
870
+ /**
871
+ * Post a comment on a track.
872
+ *
873
+ * @param trackId - The track's numeric ID or URN
874
+ * @param body - The comment text
875
+ * @param timestamp - Position in the track in milliseconds where the comment is placed
876
+ * @param options - Optional token override
877
+ * @returns The created comment object
878
+ * @throws {SoundCloudError} When the API returns an error
879
+ *
880
+ * @example
881
+ * ```ts
882
+ * const comment = await sc.tracks.createComment(123456, 'Great track!', 30000);
883
+ * console.log(comment.id);
884
+ * ```
885
+ *
886
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/post_tracks__track_id__comments
887
+ */
888
+ async createComment(trackId, body, timestamp, options) {
889
+ const t = resolveToken(this.getToken, options?.token);
890
+ return this.fetch({
891
+ path: `/tracks/${trackId}/comments`,
892
+ method: "POST",
893
+ token: t,
894
+ body: { comment: { body, ...timestamp !== void 0 ? { timestamp } : {} } }
895
+ });
896
+ }
897
+ /**
898
+ * Get users who have liked (favorited) a track.
899
+ *
900
+ * @param trackId - The track's numeric ID or URN
901
+ * @param limit - Maximum number of users per page
902
+ * @param options - Optional token override
903
+ * @returns Paginated list of users who liked the track
904
+ * @throws {SoundCloudError} When the API returns an error
905
+ *
906
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id__favoriters
907
+ */
908
+ async getLikes(trackId, limit, options) {
909
+ const t = resolveToken(this.getToken, options?.token);
910
+ return this.fetch({ path: `/tracks/${trackId}/favoriters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
911
+ }
912
+ /**
913
+ * Get users who have reposted a track.
914
+ *
915
+ * @param trackId - The track's numeric ID or URN
916
+ * @param limit - Maximum number of users per page
917
+ * @param options - Optional token override
918
+ * @returns Paginated list of users who reposted the track
919
+ * @throws {SoundCloudError} When the API returns an error
920
+ *
921
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id__reposters
922
+ */
923
+ async getReposts(trackId, limit, options) {
924
+ const t = resolveToken(this.getToken, options?.token);
925
+ return this.fetch({ path: `/tracks/${trackId}/reposters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
926
+ }
927
+ /**
928
+ * Get tracks related to a given track.
929
+ *
930
+ * @param trackId - The track's numeric ID or URN
931
+ * @param limit - Maximum number of related tracks to return
932
+ * @param options - Optional token override
933
+ * @returns Array of related tracks
934
+ * @throws {SoundCloudError} When the API returns an error
935
+ *
936
+ * @example
937
+ * ```ts
938
+ * const related = await sc.tracks.getRelated(123456, 5);
939
+ * related.forEach(t => console.log(t.title));
940
+ * ```
941
+ *
942
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks__track_id__related
943
+ */
944
+ async getRelated(trackId, limit, options) {
945
+ const t = resolveToken(this.getToken, options?.token);
946
+ return this.fetch({ path: `/tracks/${trackId}/related${limit ? `?limit=${limit}` : ""}`, method: "GET", token: t });
947
+ }
948
+ /**
949
+ * Update a track's metadata.
950
+ *
951
+ * @param trackId - The track's numeric ID or URN
952
+ * @param params - Fields to update (title, description, genre, etc.)
953
+ * @param options - Optional token override
954
+ * @returns The updated track object
955
+ * @throws {SoundCloudError} When the API returns an error
956
+ *
957
+ * @example
958
+ * ```ts
959
+ * const updated = await sc.tracks.update(123456, { title: 'New Title', genre: 'Electronic' });
960
+ * console.log(updated.title);
961
+ * ```
962
+ *
963
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/put_tracks__track_id_
964
+ */
965
+ async update(trackId, params, options) {
966
+ const t = resolveToken(this.getToken, options?.token);
967
+ return this.fetch({ path: `/tracks/${trackId}`, method: "PUT", token: t, body: { track: params } });
968
+ }
969
+ /**
970
+ * Delete a track.
971
+ *
972
+ * @param trackId - The track's numeric ID or URN
973
+ * @param options - Optional token override
974
+ * @throws {SoundCloudError} When the API returns an error
975
+ *
976
+ * @example
977
+ * ```ts
978
+ * await sc.tracks.delete(123456);
979
+ * ```
980
+ *
981
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/delete_tracks__track_id_
982
+ */
983
+ async delete(trackId, options) {
984
+ const t = resolveToken(this.getToken, options?.token);
985
+ return this.fetch({ path: `/tracks/${trackId}`, method: "DELETE", token: t });
986
+ }
987
+ }
988
+ SoundCloudClient2.Tracks = Tracks;
989
+ class Playlists {
990
+ constructor(getToken, refreshCtx) {
991
+ this.getToken = getToken;
992
+ this.refreshCtx = refreshCtx;
993
+ }
994
+ fetch(opts) {
995
+ return scFetch(opts, this.refreshCtx);
996
+ }
997
+ /**
998
+ * Get a playlist by ID.
999
+ *
1000
+ * @param playlistId - The playlist's numeric ID or URN
1001
+ * @param options - Optional token override
1002
+ * @returns The playlist object with track data
1003
+ * @throws {SoundCloudError} When the playlist is not found or the API returns an error
1004
+ *
1005
+ * @example
1006
+ * ```ts
1007
+ * const playlist = await sc.playlists.getPlaylist(123456);
1008
+ * console.log(playlist.title, playlist.track_count);
1009
+ * ```
1010
+ *
1011
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/get_playlists__playlist_id_
1012
+ */
1013
+ async getPlaylist(playlistId, options) {
1014
+ const t = resolveToken(this.getToken, options?.token);
1015
+ return this.fetch({ path: `/playlists/${playlistId}`, method: "GET", token: t });
1016
+ }
1017
+ /**
1018
+ * Get tracks in a playlist.
1019
+ *
1020
+ * @param playlistId - The playlist's numeric ID or URN
1021
+ * @param limit - Maximum number of tracks per page
1022
+ * @param offset - Number of tracks to skip (for offset-based pagination)
1023
+ * @param options - Optional token override
1024
+ * @returns Paginated list of tracks
1025
+ * @throws {SoundCloudError} When the API returns an error
1026
+ *
1027
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/get_playlists__playlist_id__tracks
1028
+ */
1029
+ async getTracks(playlistId, limit, offset, options) {
1030
+ const t = resolveToken(this.getToken, options?.token);
1031
+ return this.fetch({ path: `/playlists/${playlistId}/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true${offset ? `&offset=${offset}` : ""}`, method: "GET", token: t });
1032
+ }
1033
+ /**
1034
+ * Get users who have reposted a playlist.
1035
+ *
1036
+ * @param playlistId - The playlist's numeric ID or URN
1037
+ * @param limit - Maximum number of users per page
1038
+ * @param options - Optional token override
1039
+ * @returns Paginated list of users who reposted the playlist
1040
+ * @throws {SoundCloudError} When the API returns an error
1041
+ *
1042
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/get_playlists__playlist_id__reposters
1043
+ */
1044
+ async getReposts(playlistId, limit, options) {
1045
+ const t = resolveToken(this.getToken, options?.token);
1046
+ return this.fetch({ path: `/playlists/${playlistId}/reposters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token: t });
1047
+ }
1048
+ /**
1049
+ * Create a new playlist.
1050
+ *
1051
+ * @param params - Playlist creation parameters (title is required)
1052
+ * @param options - Optional token override
1053
+ * @returns The created playlist object
1054
+ * @throws {SoundCloudError} When the API returns an error
1055
+ *
1056
+ * @example
1057
+ * ```ts
1058
+ * const playlist = await sc.playlists.create({
1059
+ * title: 'My Favorites',
1060
+ * sharing: 'public',
1061
+ * tracks: [{ urn: 'soundcloud:tracks:123' }],
1062
+ * });
1063
+ * ```
1064
+ *
1065
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/post_playlists
1066
+ */
1067
+ async create(params, options) {
1068
+ const t = resolveToken(this.getToken, options?.token);
1069
+ return this.fetch({ path: "/playlists", method: "POST", token: t, body: { playlist: params } });
1070
+ }
1071
+ /**
1072
+ * Update a playlist's metadata or track list.
1073
+ *
1074
+ * @param playlistId - The playlist's numeric ID or URN
1075
+ * @param params - Fields to update
1076
+ * @param options - Optional token override
1077
+ * @returns The updated playlist object
1078
+ * @throws {SoundCloudError} When the API returns an error
1079
+ *
1080
+ * @example
1081
+ * ```ts
1082
+ * const updated = await sc.playlists.update(123456, { title: 'Updated Title' });
1083
+ * ```
1084
+ *
1085
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/put_playlists__playlist_id_
1086
+ */
1087
+ async update(playlistId, params, options) {
1088
+ const t = resolveToken(this.getToken, options?.token);
1089
+ return this.fetch({ path: `/playlists/${playlistId}`, method: "PUT", token: t, body: { playlist: params } });
1090
+ }
1091
+ /**
1092
+ * Delete a playlist.
1093
+ *
1094
+ * @param playlistId - The playlist's numeric ID or URN
1095
+ * @param options - Optional token override
1096
+ * @throws {SoundCloudError} When the API returns an error
1097
+ *
1098
+ * @example
1099
+ * ```ts
1100
+ * await sc.playlists.delete(123456);
1101
+ * ```
1102
+ *
1103
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/delete_playlists__playlist_id_
1104
+ */
1105
+ async delete(playlistId, options) {
1106
+ const t = resolveToken(this.getToken, options?.token);
1107
+ return this.fetch({ path: `/playlists/${playlistId}`, method: "DELETE", token: t });
1108
+ }
1109
+ }
1110
+ SoundCloudClient2.Playlists = Playlists;
1111
+ class Search {
1112
+ constructor(getToken, refreshCtx) {
1113
+ this.getToken = getToken;
1114
+ this.refreshCtx = refreshCtx;
1115
+ }
1116
+ fetch(opts) {
1117
+ return scFetch(opts, this.refreshCtx);
1118
+ }
1119
+ /**
1120
+ * Search for tracks by query string.
1121
+ *
1122
+ * @param query - Search query text
1123
+ * @param pageNumber - Zero-based page number (10 results per page)
1124
+ * @param options - Optional token override
1125
+ * @returns Paginated list of matching tracks
1126
+ * @throws {SoundCloudError} When the API returns an error
1127
+ *
1128
+ * @example
1129
+ * ```ts
1130
+ * const results = await sc.search.tracks('lofi hip hop');
1131
+ * results.collection.forEach(t => console.log(t.title));
1132
+ * ```
1133
+ *
1134
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/tracks/get_tracks
1135
+ */
1136
+ async tracks(query, pageNumber, options) {
1137
+ const t = resolveToken(this.getToken, options?.token);
1138
+ return this.fetch({ path: `/tracks?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token: t });
1139
+ }
1140
+ /**
1141
+ * Search for users by query string.
1142
+ *
1143
+ * @param query - Search query text
1144
+ * @param pageNumber - Zero-based page number (10 results per page)
1145
+ * @param options - Optional token override
1146
+ * @returns Paginated list of matching users
1147
+ * @throws {SoundCloudError} When the API returns an error
1148
+ *
1149
+ * @example
1150
+ * ```ts
1151
+ * const results = await sc.search.users('deadmau5');
1152
+ * results.collection.forEach(u => console.log(u.username));
1153
+ * ```
1154
+ *
1155
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/users/get_users
1156
+ */
1157
+ async users(query, pageNumber, options) {
1158
+ const t = resolveToken(this.getToken, options?.token);
1159
+ return this.fetch({ path: `/users?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token: t });
1160
+ }
1161
+ /**
1162
+ * Search for playlists by query string.
1163
+ *
1164
+ * @param query - Search query text
1165
+ * @param pageNumber - Zero-based page number (10 results per page)
1166
+ * @param options - Optional token override
1167
+ * @returns Paginated list of matching playlists
1168
+ * @throws {SoundCloudError} When the API returns an error
1169
+ *
1170
+ * @example
1171
+ * ```ts
1172
+ * const results = await sc.search.playlists('chill vibes');
1173
+ * results.collection.forEach(p => console.log(p.title));
1174
+ * ```
1175
+ *
1176
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/playlists/get_playlists
1177
+ */
1178
+ async playlists(query, pageNumber, options) {
1179
+ const t = resolveToken(this.getToken, options?.token);
1180
+ return this.fetch({ path: `/playlists?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token: t });
1181
+ }
1182
+ }
1183
+ SoundCloudClient2.Search = Search;
1184
+ class Resolve {
1185
+ constructor(getToken, refreshCtx) {
1186
+ this.getToken = getToken;
1187
+ this.refreshCtx = refreshCtx;
1188
+ }
1189
+ fetch(opts) {
1190
+ return scFetch(opts, this.refreshCtx);
1191
+ }
1192
+ /**
1193
+ * Resolve a SoundCloud URL to its API resource URL.
1194
+ *
1195
+ * @param url - A SoundCloud URL (e.g. "https://soundcloud.com/artist/track-name")
1196
+ * @param options - Optional token override
1197
+ * @returns The resolved API resource URL (via 302 redirect)
1198
+ * @throws {SoundCloudError} When the URL cannot be resolved
1199
+ *
1200
+ * @example
1201
+ * ```ts
1202
+ * const apiUrl = await sc.resolve.resolveUrl('https://soundcloud.com/deadmau5/strobe');
1203
+ * console.log(apiUrl); // "https://api.soundcloud.com/tracks/..."
1204
+ * ```
1205
+ *
1206
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/resolve/get_resolve
1207
+ */
1208
+ async resolveUrl(url, options) {
1209
+ const t = resolveToken(this.getToken, options?.token);
1210
+ return this.fetch({ path: `/resolve?url=${encodeURIComponent(url)}`, method: "GET", token: t });
1211
+ }
1212
+ }
1213
+ SoundCloudClient2.Resolve = Resolve;
1214
+ class Likes {
1215
+ constructor(getToken, refreshCtx) {
1216
+ this.getToken = getToken;
1217
+ this.refreshCtx = refreshCtx;
1218
+ }
1219
+ fetch(opts) {
1220
+ return scFetch(opts, this.refreshCtx);
1221
+ }
1222
+ /**
1223
+ * Like a track.
1224
+ *
1225
+ * @param trackId - The track's numeric ID or URN
1226
+ * @param options - Optional token override
1227
+ * @returns `true` if the like was successful, `false` on failure
1228
+ *
1229
+ * @example
1230
+ * ```ts
1231
+ * const success = await sc.likes.likeTrack(123456);
1232
+ * ```
1233
+ *
1234
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/likes/post_likes_tracks__track_id_
1235
+ */
1236
+ async likeTrack(trackId, options) {
1237
+ const t = resolveToken(this.getToken, options?.token);
1238
+ try {
1239
+ await this.fetch({ path: `/likes/tracks/${trackId}`, method: "POST", token: t });
1240
+ return true;
1241
+ } catch {
1242
+ return false;
1243
+ }
1244
+ }
1245
+ /**
1246
+ * Unlike a track.
1247
+ *
1248
+ * @param trackId - The track's numeric ID or URN
1249
+ * @param options - Optional token override
1250
+ * @returns `true` if the unlike was successful, `false` on failure
1251
+ *
1252
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/likes/delete_likes_tracks__track_id_
1253
+ */
1254
+ async unlikeTrack(trackId, options) {
1255
+ const t = resolveToken(this.getToken, options?.token);
1256
+ try {
1257
+ await this.fetch({ path: `/likes/tracks/${trackId}`, method: "DELETE", token: t });
1258
+ return true;
1259
+ } catch {
1260
+ return false;
1261
+ }
1262
+ }
1263
+ /**
1264
+ * Like a playlist.
1265
+ *
1266
+ * @param playlistId - The playlist's numeric ID or URN
1267
+ * @param options - Optional token override
1268
+ * @returns `true` if the like was successful, `false` on failure
1269
+ *
1270
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/likes/post_likes_playlists__playlist_id_
1271
+ */
1272
+ async likePlaylist(playlistId, options) {
1273
+ const t = resolveToken(this.getToken, options?.token);
1274
+ try {
1275
+ await this.fetch({ path: `/likes/playlists/${playlistId}`, method: "POST", token: t });
1276
+ return true;
1277
+ } catch {
1278
+ return false;
1279
+ }
1280
+ }
1281
+ /**
1282
+ * Unlike a playlist.
1283
+ *
1284
+ * @param playlistId - The playlist's numeric ID or URN
1285
+ * @param options - Optional token override
1286
+ * @returns `true` if the unlike was successful, `false` on failure
1287
+ *
1288
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/likes/delete_likes_playlists__playlist_id_
1289
+ */
1290
+ async unlikePlaylist(playlistId, options) {
1291
+ const t = resolveToken(this.getToken, options?.token);
1292
+ try {
1293
+ await this.fetch({ path: `/likes/playlists/${playlistId}`, method: "DELETE", token: t });
1294
+ return true;
1295
+ } catch {
1296
+ return false;
1297
+ }
1298
+ }
1299
+ }
1300
+ SoundCloudClient2.Likes = Likes;
1301
+ class Reposts {
1302
+ constructor(getToken, refreshCtx) {
1303
+ this.getToken = getToken;
1304
+ this.refreshCtx = refreshCtx;
1305
+ }
1306
+ fetch(opts) {
1307
+ return scFetch(opts, this.refreshCtx);
1308
+ }
1309
+ /**
1310
+ * Repost a track to your profile.
1311
+ *
1312
+ * @param trackId - The track's numeric ID or URN
1313
+ * @param options - Optional token override
1314
+ * @returns `true` if the repost was successful, `false` on failure
1315
+ *
1316
+ * @example
1317
+ * ```ts
1318
+ * const success = await sc.reposts.repostTrack(123456);
1319
+ * ```
1320
+ *
1321
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/reposts/post_reposts_tracks__track_id_
1322
+ */
1323
+ async repostTrack(trackId, options) {
1324
+ const t = resolveToken(this.getToken, options?.token);
1325
+ try {
1326
+ await this.fetch({ path: `/reposts/tracks/${trackId}`, method: "POST", token: t });
1327
+ return true;
1328
+ } catch {
1329
+ return false;
1330
+ }
1331
+ }
1332
+ /**
1333
+ * Remove a track repost from your profile.
1334
+ *
1335
+ * @param trackId - The track's numeric ID or URN
1336
+ * @param options - Optional token override
1337
+ * @returns `true` if the unrepost was successful, `false` on failure
1338
+ *
1339
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/reposts/delete_reposts_tracks__track_id_
1340
+ */
1341
+ async unrepostTrack(trackId, options) {
1342
+ const t = resolveToken(this.getToken, options?.token);
1343
+ try {
1344
+ await this.fetch({ path: `/reposts/tracks/${trackId}`, method: "DELETE", token: t });
1345
+ return true;
1346
+ } catch {
1347
+ return false;
1348
+ }
1349
+ }
1350
+ /**
1351
+ * Repost a playlist to your profile.
1352
+ *
1353
+ * @param playlistId - The playlist's numeric ID or URN
1354
+ * @param options - Optional token override
1355
+ * @returns `true` if the repost was successful, `false` on failure
1356
+ *
1357
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/reposts/post_reposts_playlists__playlist_id_
1358
+ */
1359
+ async repostPlaylist(playlistId, options) {
1360
+ const t = resolveToken(this.getToken, options?.token);
1361
+ try {
1362
+ await this.fetch({ path: `/reposts/playlists/${playlistId}`, method: "POST", token: t });
1363
+ return true;
1364
+ } catch {
1365
+ return false;
1366
+ }
1367
+ }
1368
+ /**
1369
+ * Remove a playlist repost from your profile.
1370
+ *
1371
+ * @param playlistId - The playlist's numeric ID or URN
1372
+ * @param options - Optional token override
1373
+ * @returns `true` if the unrepost was successful, `false` on failure
1374
+ *
1375
+ * @see https://developers.soundcloud.com/docs/api/explorer/open-api#/reposts/delete_reposts_playlists__playlist_id_
1376
+ */
1377
+ async unrepostPlaylist(playlistId, options) {
1378
+ const t = resolveToken(this.getToken, options?.token);
1379
+ try {
1380
+ await this.fetch({ path: `/reposts/playlists/${playlistId}`, method: "DELETE", token: t });
1381
+ return true;
1382
+ } catch {
1383
+ return false;
1384
+ }
1385
+ }
1386
+ }
1387
+ SoundCloudClient2.Reposts = Reposts;
1388
+ })(exports.SoundCloudClient || (exports.SoundCloudClient = {}));
1389
+
1390
+ // src/auth/getClientToken.ts
1391
+ var getClientToken = (clientId, clientSecret) => {
1392
+ return scFetch({
1393
+ path: "/oauth2/token",
1394
+ method: "POST",
1395
+ body: new URLSearchParams({
1396
+ grant_type: "client_credentials",
1397
+ client_id: clientId,
1398
+ client_secret: clientSecret
1399
+ })
1400
+ });
1401
+ };
1402
+
1403
+ // src/auth/getUserToken.ts
1404
+ var getUserToken = (clientId, clientSecret, redirectUri, code, codeVerifier) => {
1405
+ const params = {
1406
+ grant_type: "authorization_code",
1407
+ client_id: clientId,
1408
+ client_secret: clientSecret,
1409
+ redirect_uri: redirectUri,
1410
+ code
1411
+ };
1412
+ if (codeVerifier) params.code_verifier = codeVerifier;
1413
+ return scFetch({
1414
+ path: "/oauth2/token",
1415
+ method: "POST",
1416
+ body: new URLSearchParams(params)
1417
+ });
1418
+ };
1419
+
1420
+ // src/auth/refreshUserToken.ts
1421
+ var refreshUserToken = (clientId, clientSecret, redirectUri, refreshToken) => {
1422
+ return scFetch({
1423
+ path: "/oauth2/token",
1424
+ method: "POST",
1425
+ body: new URLSearchParams({
1426
+ grant_type: "refresh_token",
1427
+ client_id: clientId,
1428
+ client_secret: clientSecret,
1429
+ redirect_uri: redirectUri,
1430
+ refresh_token: refreshToken
1431
+ })
1432
+ });
1433
+ };
1434
+
1435
+ // src/auth/signOut.ts
1436
+ var signOut = async (accessToken) => {
1437
+ const res = await fetch("https://secure.soundcloud.com/sign-out", {
1438
+ method: "POST",
1439
+ headers: { "Content-Type": "application/json" },
1440
+ body: JSON.stringify({ access_token: accessToken })
1441
+ });
1442
+ if (!res.ok) throw new Error(`Sign-out failed: ${res.status}`);
1443
+ };
1444
+
1445
+ // src/auth/getAuthorizationUrl.ts
1446
+ function getAuthorizationUrl(clientId, redirectUri, options) {
1447
+ const params = new URLSearchParams({
1448
+ client_id: clientId,
1449
+ redirect_uri: redirectUri,
1450
+ response_type: "code"
1451
+ });
1452
+ if (options?.state) params.set("state", options.state);
1453
+ if (options?.codeChallenge) {
1454
+ params.set("code_challenge", options.codeChallenge);
1455
+ params.set("code_challenge_method", "S256");
1456
+ }
1457
+ return `https://api.soundcloud.com/connect?${params}`;
1458
+ }
1459
+
1460
+ // src/auth/pkce.ts
1461
+ function generateCodeVerifier() {
1462
+ const bytes = new Uint8Array(32);
1463
+ globalThis.crypto.getRandomValues(bytes);
1464
+ return base64url(bytes);
1465
+ }
1466
+ async function generateCodeChallenge(verifier) {
1467
+ const data = new TextEncoder().encode(verifier);
1468
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", data);
1469
+ return base64url(new Uint8Array(digest));
1470
+ }
1471
+ function base64url(bytes) {
1472
+ let binary = "";
1473
+ for (const b of bytes) binary += String.fromCharCode(b);
1474
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1475
+ }
1476
+
1477
+ // src/users/getMe.ts
1478
+ var getMe = (token) => scFetch({ path: "/me", method: "GET", token });
1479
+
1480
+ // src/users/getUser.ts
1481
+ var getUser = (token, userId) => scFetch({ path: `/users/${userId}`, method: "GET", token });
1482
+
1483
+ // src/users/getFollowers.ts
1484
+ var getFollowers = (token, userId, limit) => scFetch({ path: `/users/${userId}/followers?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1485
+
1486
+ // src/users/getFollowings.ts
1487
+ var getFollowings = (token, userId, limit) => scFetch({ path: `/users/${userId}/followings?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1488
+
1489
+ // src/users/getTracks.ts
1490
+ var getUserTracks = (token, userId, limit) => scFetch({ path: `/users/${userId}/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1491
+
1492
+ // src/users/getPlaylists.ts
1493
+ var getUserPlaylists = (token, userId, limit) => scFetch({ path: `/users/${userId}/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true&show_tracks=false`, method: "GET", token });
1494
+
1495
+ // src/users/getLikesTracks.ts
1496
+ var getUserLikesTracks = (token, userId, limit, cursor) => scFetch({ path: `/users/${userId}/likes/tracks?${limit ? `limit=${limit}&` : ""}${cursor ? `cursor=${cursor}&` : ""}linked_partitioning=true`, method: "GET", token });
1497
+
1498
+ // src/users/getLikesPlaylists.ts
1499
+ var getUserLikesPlaylists = (token, userId, limit) => scFetch({ path: `/users/${userId}/likes/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1500
+
1501
+ // src/users/getWebProfiles.ts
1502
+ var getUserWebProfiles = (token, userId) => scFetch({ path: `/users/${userId}/web-profiles`, method: "GET", token });
1503
+
1504
+ // src/tracks/getTrack.ts
1505
+ var getTrack = (token, trackId) => scFetch({ path: `/tracks/${trackId}`, method: "GET", token });
1506
+
1507
+ // src/tracks/getComments.ts
1508
+ var getTrackComments = (token, trackId, limit) => scFetch({ path: `/tracks/${trackId}/comments?threaded=1&filter_replies=0${limit ? `&limit=${limit}` : ""}&linked_partitioning=true`, method: "GET", token });
1509
+
1510
+ // src/tracks/createComment.ts
1511
+ var createTrackComment = (token, trackId, body, timestamp) => scFetch({
1512
+ path: `/tracks/${trackId}/comments`,
1513
+ method: "POST",
1514
+ token,
1515
+ body: { comment: { body, ...timestamp !== void 0 ? { timestamp } : {} } }
1516
+ });
1517
+
1518
+ // src/tracks/getLikes.ts
1519
+ var getTrackLikes = (token, trackId, limit) => scFetch({ path: `/tracks/${trackId}/favoriters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1520
+
1521
+ // src/tracks/getReposts.ts
1522
+ var getTrackReposts = (token, trackId, limit) => scFetch({ path: `/tracks/${trackId}/reposters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1523
+
1524
+ // src/tracks/getRelated.ts
1525
+ var getRelatedTracks = (token, trackId, limit) => scFetch({ path: `/tracks/${trackId}/related${limit ? `?limit=${limit}` : ""}`, method: "GET", token });
1526
+
1527
+ // src/tracks/getStreams.ts
1528
+ var getTrackStreams = (token, trackId) => scFetch({ path: `/tracks/${trackId}/streams`, method: "GET", token });
1529
+
1530
+ // src/tracks/likeTrack.ts
1531
+ var likeTrack = async (token, trackId) => {
1532
+ try {
1533
+ await scFetch({ path: `/likes/tracks/${trackId}`, method: "POST", token });
1534
+ return true;
1535
+ } catch {
1536
+ return false;
1537
+ }
1538
+ };
1539
+
1540
+ // src/tracks/unlikeTrack.ts
1541
+ var unlikeTrack = async (token, trackId) => {
1542
+ try {
1543
+ await scFetch({ path: `/likes/tracks/${trackId}`, method: "DELETE", token });
1544
+ return true;
1545
+ } catch {
1546
+ return false;
1547
+ }
1548
+ };
1549
+
1550
+ // src/tracks/updateTrack.ts
1551
+ var updateTrack = (token, trackId, params) => scFetch({
1552
+ path: `/tracks/${trackId}`,
1553
+ method: "PUT",
1554
+ token,
1555
+ body: { track: params }
1556
+ });
1557
+
1558
+ // src/tracks/deleteTrack.ts
1559
+ var deleteTrack = (token, trackId) => scFetch({ path: `/tracks/${trackId}`, method: "DELETE", token });
1560
+
1561
+ // src/playlists/getPlaylist.ts
1562
+ var getPlaylist = (token, playlistId) => scFetch({ path: `/playlists/${playlistId}`, method: "GET", token });
1563
+
1564
+ // src/playlists/getTracks.ts
1565
+ var getPlaylistTracks = (token, playlistId, limit, offset) => scFetch({ path: `/playlists/${playlistId}/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true${offset ? `&offset=${offset}` : ""}`, method: "GET", token });
1566
+
1567
+ // src/playlists/getReposts.ts
1568
+ var getPlaylistReposts = (token, playlistId, limit) => scFetch({ path: `/playlists/${playlistId}/reposters?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1569
+
1570
+ // src/playlists/createPlaylist.ts
1571
+ var createPlaylist = (token, params) => scFetch({
1572
+ path: "/playlists",
1573
+ method: "POST",
1574
+ token,
1575
+ body: { playlist: params }
1576
+ });
1577
+
1578
+ // src/playlists/updatePlaylist.ts
1579
+ var updatePlaylist = (token, playlistId, params) => scFetch({
1580
+ path: `/playlists/${playlistId}`,
1581
+ method: "PUT",
1582
+ token,
1583
+ body: { playlist: params }
1584
+ });
1585
+
1586
+ // src/playlists/deletePlaylist.ts
1587
+ var deletePlaylist = (token, playlistId) => scFetch({ path: `/playlists/${playlistId}`, method: "DELETE", token });
1588
+
1589
+ // src/search/searchTracks.ts
1590
+ var searchTracks = (token, query, pageNumber) => scFetch({ path: `/tracks?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token });
1591
+
1592
+ // src/search/searchUsers.ts
1593
+ var searchUsers = (token, query, pageNumber) => scFetch({ path: `/users?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token });
1594
+
1595
+ // src/search/searchPlaylists.ts
1596
+ var searchPlaylists = (token, query, pageNumber) => scFetch({ path: `/playlists?q=${encodeURIComponent(query)}&linked_partitioning=true&limit=10${pageNumber && pageNumber > 0 ? `&offset=${10 * pageNumber}` : ""}`, method: "GET", token });
1597
+
1598
+ // src/resolve/resolveUrl.ts
1599
+ var resolveUrl = (token, url) => scFetch({ path: `/resolve?url=${encodeURIComponent(url)}`, method: "GET", token });
1600
+
1601
+ // src/me/activities.ts
1602
+ var getMeActivities = (token, limit) => scFetch({ path: `/me/activities?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1603
+ var getMeActivitiesOwn = (token, limit) => scFetch({ path: `/me/activities/all/own?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1604
+ var getMeActivitiesTracks = (token, limit) => scFetch({ path: `/me/activities/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1605
+
1606
+ // src/me/likes.ts
1607
+ var getMeLikesTracks = (token, limit) => scFetch({ path: `/me/likes/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1608
+ var getMeLikesPlaylists = (token, limit) => scFetch({ path: `/me/likes/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1609
+
1610
+ // src/me/followings.ts
1611
+ var getMeFollowings = (token, limit) => scFetch({ path: `/me/followings?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1612
+ var getMeFollowingsTracks = (token, limit) => scFetch({ path: `/me/followings/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1613
+ var followUser = (token, userUrn) => scFetch({ path: `/me/followings/${userUrn}`, method: "PUT", token });
1614
+ var unfollowUser = (token, userUrn) => scFetch({ path: `/me/followings/${userUrn}`, method: "DELETE", token });
1615
+
1616
+ // src/me/followers.ts
1617
+ var getMeFollowers = (token, limit) => scFetch({ path: `/me/followers?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1618
+
1619
+ // src/me/playlists.ts
1620
+ var getMePlaylists = (token, limit) => scFetch({ path: `/me/playlists?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1621
+
1622
+ // src/me/tracks.ts
1623
+ var getMeTracks = (token, limit) => scFetch({ path: `/me/tracks?${limit ? `limit=${limit}&` : ""}linked_partitioning=true`, method: "GET", token });
1624
+
1625
+ // src/likes/index.ts
1626
+ var likePlaylist = async (token, playlistId) => {
1627
+ try {
1628
+ await scFetch({ path: `/likes/playlists/${playlistId}`, method: "POST", token });
1629
+ return true;
1630
+ } catch {
1631
+ return false;
1632
+ }
1633
+ };
1634
+ var unlikePlaylist = async (token, playlistId) => {
1635
+ try {
1636
+ await scFetch({ path: `/likes/playlists/${playlistId}`, method: "DELETE", token });
1637
+ return true;
1638
+ } catch {
1639
+ return false;
1640
+ }
1641
+ };
1642
+
1643
+ // src/reposts/index.ts
1644
+ var repostTrack = async (token, trackId) => {
1645
+ try {
1646
+ await scFetch({ path: `/reposts/tracks/${trackId}`, method: "POST", token });
1647
+ return true;
1648
+ } catch {
1649
+ return false;
1650
+ }
1651
+ };
1652
+ var unrepostTrack = async (token, trackId) => {
1653
+ try {
1654
+ await scFetch({ path: `/reposts/tracks/${trackId}`, method: "DELETE", token });
1655
+ return true;
1656
+ } catch {
1657
+ return false;
1658
+ }
1659
+ };
1660
+ var repostPlaylist = async (token, playlistId) => {
1661
+ try {
1662
+ await scFetch({ path: `/reposts/playlists/${playlistId}`, method: "POST", token });
1663
+ return true;
1664
+ } catch {
1665
+ return false;
1666
+ }
1667
+ };
1668
+ var unrepostPlaylist = async (token, playlistId) => {
1669
+ try {
1670
+ await scFetch({ path: `/reposts/playlists/${playlistId}`, method: "DELETE", token });
1671
+ return true;
1672
+ } catch {
1673
+ return false;
1674
+ }
1675
+ };
1676
+
1677
+ // src/utils/widget.ts
1678
+ var getSoundCloudWidgetUrl = (trackId) => `https%3A//api.soundcloud.com/tracks/${trackId}&show_teaser=false&color=%2300a99d&inverse=false&show_user=false&sharing=false&buying=false&liking=false&show_artwork=false&show_name=false`;
1679
+
1680
+ exports.createPlaylist = createPlaylist;
1681
+ exports.createTrackComment = createTrackComment;
1682
+ exports.deletePlaylist = deletePlaylist;
1683
+ exports.deleteTrack = deleteTrack;
1684
+ exports.fetchAll = fetchAll;
1685
+ exports.followUser = followUser;
1686
+ exports.generateCodeChallenge = generateCodeChallenge;
1687
+ exports.generateCodeVerifier = generateCodeVerifier;
1688
+ exports.getAuthorizationUrl = getAuthorizationUrl;
1689
+ exports.getClientToken = getClientToken;
1690
+ exports.getFollowers = getFollowers;
1691
+ exports.getFollowings = getFollowings;
1692
+ exports.getMe = getMe;
1693
+ exports.getMeActivities = getMeActivities;
1694
+ exports.getMeActivitiesOwn = getMeActivitiesOwn;
1695
+ exports.getMeActivitiesTracks = getMeActivitiesTracks;
1696
+ exports.getMeFollowers = getMeFollowers;
1697
+ exports.getMeFollowings = getMeFollowings;
1698
+ exports.getMeFollowingsTracks = getMeFollowingsTracks;
1699
+ exports.getMeLikesPlaylists = getMeLikesPlaylists;
1700
+ exports.getMeLikesTracks = getMeLikesTracks;
1701
+ exports.getMePlaylists = getMePlaylists;
1702
+ exports.getMeTracks = getMeTracks;
1703
+ exports.getPlaylist = getPlaylist;
1704
+ exports.getPlaylistReposts = getPlaylistReposts;
1705
+ exports.getPlaylistTracks = getPlaylistTracks;
1706
+ exports.getRelatedTracks = getRelatedTracks;
1707
+ exports.getSoundCloudWidgetUrl = getSoundCloudWidgetUrl;
1708
+ exports.getTrack = getTrack;
1709
+ exports.getTrackComments = getTrackComments;
1710
+ exports.getTrackLikes = getTrackLikes;
1711
+ exports.getTrackReposts = getTrackReposts;
1712
+ exports.getTrackStreams = getTrackStreams;
1713
+ exports.getUser = getUser;
1714
+ exports.getUserLikesPlaylists = getUserLikesPlaylists;
1715
+ exports.getUserLikesTracks = getUserLikesTracks;
1716
+ exports.getUserPlaylists = getUserPlaylists;
1717
+ exports.getUserToken = getUserToken;
1718
+ exports.getUserTracks = getUserTracks;
1719
+ exports.getUserWebProfiles = getUserWebProfiles;
1720
+ exports.likePlaylist = likePlaylist;
1721
+ exports.likeTrack = likeTrack;
1722
+ exports.paginate = paginate;
1723
+ exports.paginateItems = paginateItems;
1724
+ exports.refreshUserToken = refreshUserToken;
1725
+ exports.repostPlaylist = repostPlaylist;
1726
+ exports.repostTrack = repostTrack;
1727
+ exports.resolveUrl = resolveUrl;
1728
+ exports.scFetch = scFetch;
1729
+ exports.scFetchUrl = scFetchUrl;
1730
+ exports.searchPlaylists = searchPlaylists;
1731
+ exports.searchTracks = searchTracks;
1732
+ exports.searchUsers = searchUsers;
1733
+ exports.signOut = signOut;
1734
+ exports.unfollowUser = unfollowUser;
1735
+ exports.unlikePlaylist = unlikePlaylist;
1736
+ exports.unlikeTrack = unlikeTrack;
1737
+ exports.unrepostPlaylist = unrepostPlaylist;
1738
+ exports.unrepostTrack = unrepostTrack;
1739
+ exports.updatePlaylist = updatePlaylist;
1740
+ exports.updateTrack = updateTrack;
1741
+ //# sourceMappingURL=chunk-LNMDNQSC.js.map
1742
+ //# sourceMappingURL=chunk-LNMDNQSC.js.map