soundcloud

soundcloud.py

Tests Coverage Status Supported Python Versions Version License Monthly Downloads

Python wrapper for some of the internal v2 SoundCloud API (read/GET only methods). Does not require an API key.

Note: This is NOT the official SoundCloud developer API

SoundCloud is not accepting any more application registration requests 1 so I made this library so developers can use SoundCloud's internal API for their projects.

Installation

pip install soundcloud-v2

Documentation

https://7x11x13.xyz/soundcloud.py

Example

from soundcloud import SoundCloud

sc = SoundCloud(auth_token="auth_token")
assert sc.is_client_id_valid()
assert sc.is_auth_token_valid()
me = sc.get_user_by_username("7x11x13")
assert me.permalink == "7x11x13"

Notes on auth_token

Some methods require authentication in the form of an OAuth2 access token. You can find your token in your browser cookies for SoundCloud under the name "oauth_token". A new token will be generated each time you log out and log back in.

Notes on **kwargs

All API methods have a **kwargs argument which you can use to pass extra, undocumented arguments to the SoundCloud v2 API in case I missed some parameter which you find useful. If this is the case, feel free to create an issue or pull request to document the missing argument.

License

MIT

 1# ruff: noqa
 2"""
 3# soundcloud.py
 4
 5[![Tests](https://github.com/7x11x13/soundcloud.py/actions/workflows/ci.yml/badge.svg)](https://github.com/7x11x13/soundcloud.py/actions/workflows/ci.yml)
 6[![Coverage Status](https://coveralls.io/repos/github/7x11x13/soundcloud.py/badge.svg?branch=main)](https://coveralls.io/github/7x11x13/soundcloud.py?branch=main)
 7[![Supported Python Versions](https://img.shields.io/badge/python-3.7%2C%203.8%2C%203.9%2C%203.10%2C%203.11%2C%203.12-blue.svg)](https://pypi.org/project/soundcloud-v2/)
 8[![Version](https://img.shields.io/pypi/v/soundcloud-v2.svg)](https://pypi.org/project/soundcloud-v2/)
 9[![License](https://img.shields.io/pypi/l/soundcloud-v2.svg)](https://pypi.org/project/soundcloud-v2/)
10[![Monthly Downloads](https://pepy.tech/badge/soundcloud-v2/month)](https://pepy.tech/project/soundcloud-v2)
11
12Python wrapper for some of the internal v2 SoundCloud API (read/GET only methods). Does not require an API key.
13
14### Note: This is NOT the official [SoundCloud developer API](https://developers.soundcloud.com/docs/api/guide)
15
16SoundCloud is not accepting any more application registration requests [^1] so
17I made this library so developers can use SoundCloud's internal API for their projects.
18
19
20[^1]: https://docs.google.com/forms/d/e/1FAIpQLSfNxc82RJuzC0DnISat7n4H-G7IsPQIdaMpe202iiHZEoso9w/closedform
21
22## Installation
23
24```bash
25pip install soundcloud-v2
26```
27
28## Documentation
29
30https://7x11x13.xyz/soundcloud.py
31
32## Example
33
34```python
35from soundcloud import SoundCloud
36
37sc = SoundCloud(auth_token="auth_token")
38assert sc.is_client_id_valid()
39assert sc.is_auth_token_valid()
40me = sc.get_user_by_username("7x11x13")
41assert me.permalink == "7x11x13"
42```
43
44## Notes on `auth_token`
45Some methods require authentication in the form of an OAuth2 access token.
46You can find your token in your browser cookies for SoundCloud under the name "oauth_token".
47A new token will be generated each time you log out and log back in.
48
49## Notes on `**kwargs`
50All API methods have a `**kwargs` argument which you can use to pass extra, undocumented
51arguments to the SoundCloud v2 API in case I missed some parameter which you find useful.
52If this is the case, feel free to create an issue or pull request to document the missing
53argument.
54
55## License
56[MIT](https://choosealicense.com/licenses/mit/)
57
58"""
59
60from soundcloud.exceptions import *
61from soundcloud.exceptions import __all__ as ex_all
62from soundcloud.resource import *
63from soundcloud.resource import __all__ as res_all
64from soundcloud.soundcloud import *
65from soundcloud.soundcloud import __all__ as sc_all
66
67__version__ = "1.7.0"
68
69__all__ = sc_all + ex_all + res_all
class SoundCloud:
 71class SoundCloud:
 72    """
 73    SoundCloud v2 API client
 74    """
 75
 76    _DEFAULT_USER_AGENT = (
 77        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0"
 78    )
 79    _ASSETS_SCRIPTS_REGEX = re.compile(
 80        r"src=\"(https:\/\/a-v2\.sndcdn\.com/assets/.*\.js)\""
 81    )
 82    _CLIENT_ID_REGEX = re.compile(r"client_id:\"([^\"]+)\"")
 83    client_id: str
 84    """SoundCloud client ID. Needed for all requests."""
 85    _user_agent: str
 86    _auth_token: Optional[str]
 87    _authorization: Optional[str]
 88
 89    def __init__(
 90        self,
 91        client_id: Optional[str] = None,
 92        auth_token: Optional[str] = None,
 93        user_agent: str = _DEFAULT_USER_AGENT,
 94        impersonate: BrowserTypeLiteral = "chrome",
 95    ) -> None:
 96        self._impersonate = impersonate
 97        self._session: requests.Session = requests.Session(impersonate=impersonate)
 98        if not client_id:
 99            client_id = self.generate_client_id(impersonate=impersonate)
100
101        self.client_id = client_id
102        self._user_agent = user_agent
103        self._auth_token = None
104        self._authorization = None
105        self.auth_token = auth_token
106
107    @property
108    def auth_token(self) -> Optional[str]:
109        """SoundCloud auth token. Only needed for some requests."""
110        return self._auth_token
111
112    @auth_token.setter
113    def auth_token(self, new_auth_token: Optional[str]) -> None:
114        if new_auth_token is not None:
115            if new_auth_token.startswith("OAuth"):
116                new_auth_token = new_auth_token.split()[-1]
117        self._authorization = f"OAuth {new_auth_token}" if new_auth_token else None
118        self._auth_token = new_auth_token
119
120    @auth_token.deleter
121    def auth_token(self):
122        self.auth_token = None
123
124    def _get_default_headers(self) -> Dict[str, str]:
125        return {"User-Agent": self._user_agent}
126
127    @classmethod
128    def generate_client_id(cls, impersonate: BrowserTypeLiteral = "chrome") -> str:
129        """Generates a SoundCloud client ID
130
131        Raises:
132            ClientIDGenerationError: Client ID could not be generated.
133
134        Returns:
135            str: Valid client ID
136        """
137        with requests.Session(impersonate=impersonate) as s:
138            r = s.get("https://soundcloud.com")
139            r.raise_for_status()
140            matches = cls._ASSETS_SCRIPTS_REGEX.findall(r.text)
141            if not matches:
142                raise ClientIDGenerationError("No asset scripts found")
143            for url in matches:
144                r = s.get(url)
145                r.raise_for_status()
146                client_id = cls._CLIENT_ID_REGEX.search(r.text)
147                if client_id:
148                    return client_id.group(1)
149            raise ClientIDGenerationError(f"Could not find client_id in script '{url}'")
150
151    def is_client_id_valid(self) -> bool:
152        """
153        Checks if current client_id is valid
154        """
155        try:
156            TrackRequest(self, track_id=1032303631, use_auth=False)
157            return True
158        except HTTPError as err:
159            if err.response.status_code == 401:
160                return False
161            else:
162                raise
163
164    def is_auth_token_valid(self) -> bool:
165        """
166        Checks if current auth_token is valid
167        """
168        try:
169            MeRequest(self)
170            return True
171        except HTTPError as err:
172            if err.response.status_code == 401:
173                return False
174            else:
175                raise
176
177    def get_me(self) -> Optional[User]:
178        """
179        Gets the user associated with client's auth token
180        """
181        return MeRequest(self)
182
183    def get_my_history(self, **kwargs) -> Generator[HistoryItem, None, None]:
184        """
185        Returns the stream of recently listened tracks
186        for the client's auth token
187        """
188        return MeHistoryRequest(self, **kwargs)
189
190    def get_my_stream(self, **kwargs) -> Generator[StreamItem, None, None]:
191        """
192        Returns the stream of recent uploads/reposts
193        for the client's auth token
194        """
195        return MeStreamRequest(self, **kwargs)
196
197    def resolve(self, url: str) -> Optional[SearchItem]:
198        """
199        Returns the resource at the given URL if it
200        exists, otherwise return None
201        """
202        return ResolveRequest(self, url=url)
203
204    def search(self, query: str, **kwargs) -> Generator[SearchItem, None, None]:
205        """
206        Search for users, tracks, and playlists
207        """
208        return SearchRequest(self, q=query, **kwargs)
209
210    def search_albums(
211        self, query: str, **kwargs
212    ) -> Generator[AlbumPlaylist, None, None]:
213        """
214        Search for albums (not playlists)
215        """
216        return SearchAlbumsRequest(self, q=query, **kwargs)
217
218    def search_playlists(
219        self, query: str, **kwargs
220    ) -> Generator[AlbumPlaylist, None, None]:
221        """
222        Search for playlists
223        """
224        return SearchPlaylistsRequest(self, q=query, **kwargs)
225
226    def search_tracks(self, query: str, **kwargs) -> Generator[Track, None, None]:
227        """
228        Search for tracks
229        """
230        return SearchTracksRequest(self, q=query, **kwargs)
231
232    def search_users(self, query: str, **kwargs) -> Generator[User, None, None]:
233        """
234        Search for users
235        """
236        return SearchUsersRequest(self, q=query, **kwargs)
237
238    def get_tag_tracks_recent(self, tag: str, **kwargs) -> Generator[Track, None, None]:
239        """
240        Get most recent tracks for this tag
241        """
242        return TagRecentTracksRequest(self, tag=tag, **kwargs)
243
244    def get_playlist(self, playlist_id: int) -> Optional[BasicAlbumPlaylist]:
245        """
246        Returns the playlist with the given playlist_id.
247        If the ID is invalid, return None
248        """
249        return PlaylistRequest(self, playlist_id=playlist_id)
250
251    def post_playlist(
252        self, sharing: Literal["private", "public"], title: str, tracks: List[int]
253    ) -> Optional[BasicAlbumPlaylist]:
254        """
255        Create a new playlist
256        """
257        body = {"playlist": {"sharing": sharing, "title": title, "tracks": tracks}}
258        return PostPlaylistRequest(self, body=body)
259
260    def delete_playlist(self, playlist_id: int) -> Optional[NoContentResponse]:
261        """
262        Delete a playlist
263        """
264        return DeletePlaylistRequest(self, playlist_id=playlist_id)
265
266    def get_playlist_likers(
267        self, playlist_id: int, **kwargs
268    ) -> Generator[User, None, None]:
269        """
270        Get people who liked this playlist
271        """
272        return PlaylistLikersRequest(self, playlist_id=playlist_id, **kwargs)
273
274    def get_playlist_reposters(
275        self, playlist_id: int, **kwargs
276    ) -> Generator[User, None, None]:
277        """
278        Get people who reposted this playlist
279        """
280        return PlaylistRepostersRequest(self, playlist_id=playlist_id, **kwargs)
281
282    def get_track(self, track_id: int) -> Optional[BasicTrack]:
283        """
284        Returns the track with the given track_id.
285        If the ID is invalid, return None
286        """
287        return TrackRequest(self, track_id=track_id)
288
289    def get_tracks(
290        self,
291        track_ids: List[int],
292        playlistId: Optional[int] = None,
293        playlistSecretToken: Optional[str] = None,
294        **kwargs,
295    ) -> List[BasicTrack]:
296        """
297        Returns the tracks with the given track_ids.
298        Can be used to get track info for hidden tracks in a hidden playlist.
299        """
300        if playlistId is not None:
301            kwargs["playlistId"] = playlistId
302        if playlistSecretToken is not None:
303            kwargs["playlistSecretToken"] = playlistSecretToken
304        return TracksRequest(
305            self, ids=",".join([str(id) for id in track_ids]), **kwargs
306        )
307
308    def get_track_albums(
309        self, track_id: int, **kwargs
310    ) -> Generator[BasicAlbumPlaylist, None, None]:
311        """
312        Get albums that this track is in
313        """
314        return TrackAlbumsRequest(self, track_id=track_id, **kwargs)
315
316    def get_track_playlists(
317        self, track_id: int, **kwargs
318    ) -> Generator[BasicAlbumPlaylist, None, None]:
319        """
320        Get playlists that this track is in
321        """
322        return TrackPlaylistsRequest(self, track_id=track_id, **kwargs)
323
324    def get_track_comments(
325        self, track_id: int, threaded: int = 0, **kwargs
326    ) -> Generator[BasicComment, None, None]:
327        """
328        Get comments on this track
329        """
330        return TrackCommentsRequest(
331            self, track_id=track_id, threaded=threaded, **kwargs
332        )
333
334    def get_track_comments_with_interactions(
335        self, track_id: int, threaded: int = 0, **kwargs
336    ) -> Generator[CommentWithInteractions, None, None]:
337        """
338        Get comments on this track with interaction data. Requires authentication.
339        """
340        track = self.get_track(track_id)
341        if not track:
342            return
343        track_urn = track.urn
344        creator_urn = track.user.urn
345        comments = self.get_track_comments(track_id, threaded, **kwargs)
346        while True:
347            chunk = list(itertools.islice(comments, 10))
348            if not chunk:
349                return
350            comment_urns = [comment.self.urn for comment in chunk]
351            result = UserInteractionsRequest(
352                self,
353                UserInteractionsQueryParams(
354                    creator_urn,
355                    "sc:interactiontype:reaction",
356                    track_urn,
357                    comment_urns,
358                ),
359            )
360            if not result:
361                return
362            comments_with_interactions = []
363            for comment, user_interactions, creator_interactions in zip(
364                chunk, result.user, result.creator
365            ):
366                assert user_interactions.interactionCounts is not None
367                likes = list(
368                    filter(
369                        lambda x: (
370                            x.interactionTypeValueUrn == "sc:interactiontypevalue:like"
371                        ),
372                        user_interactions.interactionCounts,
373                    )
374                )
375                num_likes = likes[0].count if likes else 0
376                comments_with_interactions.append(
377                    CommentWithInteractions(
378                        comment=comment,
379                        likes=num_likes or 0,
380                        liked_by_creator=creator_interactions.userInteraction
381                        == "sc:interactiontypevalue:like",
382                        liked_by_user=user_interactions.userInteraction
383                        == "sc:interactiontypevalue:like",
384                    )
385                )
386            yield from comments_with_interactions
387
388    def get_track_likers(self, track_id: int, **kwargs) -> Generator[User, None, None]:
389        """
390        Get users who liked this track
391        """
392        return TrackLikersRequest(self, track_id=track_id, **kwargs)
393
394    def get_track_related(
395        self, track_id: int, **kwargs
396    ) -> Generator[BasicTrack, None, None]:
397        """
398        Get related tracks
399        """
400        return TrackRelatedRequest(self, track_id=track_id, **kwargs)
401
402    def get_track_reposters(
403        self, track_id: int, **kwargs
404    ) -> Generator[User, None, None]:
405        """
406        Get users who reposted this track
407        """
408        return TrackRepostersRequest(self, track_id=track_id, **kwargs)
409
410    def get_track_original_download(
411        self, track_id: int, token: Optional[str] = None
412    ) -> Optional[str]:
413        """
414        Get track original download link. If track is private,
415        requires secret token to be provided (last part of secret URL).
416        Requires authentication.
417        """
418        if token is not None:
419            download = TrackOriginalDownloadRequest(
420                self, track_id=track_id, secret_token=token
421            )
422        else:
423            download = TrackOriginalDownloadRequest(self, track_id=track_id)
424        if download is None:
425            return None
426        else:
427            return download.redirectUri
428
429    def get_user(self, user_id: int) -> Optional[User]:
430        """
431        Returns the user with the given user_id.
432        If the ID is invalid, return None
433        """
434        return UserRequest(self, user_id=user_id)
435
436    def get_user_by_username(self, username: str) -> Optional[User]:
437        """
438        Returns the user with the given username.
439        If the username is invalid, return None
440        """
441        resource = self.resolve(f"https://soundcloud.com/{username}")
442        if resource and isinstance(resource, User):
443            return resource
444        else:
445            return None
446
447    def get_user_comments(
448        self, user_id: int, **kwargs
449    ) -> Generator[Comment, None, None]:
450        """
451        Get comments by this user
452        """
453        return UserCommentsRequest(self, user_id=user_id, **kwargs)
454
455    def get_conversation_messages(
456        self, user_id: int, conversation_id: int, **kwargs
457    ) -> Generator[Message, None, None]:
458        """
459        Get messages in this conversation
460        """
461        return UserConversationMessagesRequest(
462            self, user_id=user_id, conversation_id=conversation_id, **kwargs
463        )
464
465    def get_conversations(
466        self, user_id: int, **kwargs
467    ) -> Generator[Conversation, None, None]:
468        """
469        Get conversations including this user
470        """
471        return UserConversationsRequest(self, user_id=user_id, **kwargs)
472
473    def get_unread_conversations(
474        self, user_id: int, **kwargs
475    ) -> Generator[Conversation, None, None]:
476        """
477        Get conversations unread by this user
478        """
479        return UserConversationsUnreadRequest(self, user_id=user_id, **kwargs)
480
481    def get_user_emails(
482        self, user_id: int, **kwargs
483    ) -> Generator[UserEmail, None, None]:
484        """
485        Get user's email addresses. Requires authentication.
486        """
487        return UserEmailsRequest(self, user_id=user_id, **kwargs)
488
489    def get_user_featured_profiles(
490        self, user_id: int, **kwargs
491    ) -> Generator[User, None, None]:
492        """
493        Get profiles featured by this user
494        """
495        return UserFeaturedProfilesRequest(self, user_id=user_id, **kwargs)
496
497    def get_user_followers(self, user_id: int, **kwargs) -> Generator[User, None, None]:
498        """
499        Get user's followers
500        """
501        return UserFollowersRequest(self, user_id=user_id, **kwargs)
502
503    def get_user_following(self, user_id: int, **kwargs) -> Generator[User, None, None]:
504        """
505        Get users this user is following
506        """
507        return UserFollowingsRequest(self, user_id=user_id, **kwargs)
508
509    def get_user_likes(self, user_id: int, **kwargs) -> Generator[Like, None, None]:
510        """
511        Get likes by this user
512        """
513        return UserLikesRequest(self, user_id=user_id, **kwargs)
514
515    def get_user_related_artists(
516        self, user_id: int, **kwargs
517    ) -> Generator[User, None, None]:
518        """
519        Get artists related to this user
520        """
521        return UserRelatedArtistsRequest(self, user_id=user_id, **kwargs)
522
523    def get_user_reposts(
524        self, user_id: int, **kwargs
525    ) -> Generator[RepostItem, None, None]:
526        """
527        Get reposts by this user
528        """
529        return UserRepostsRequest(self, user_id=user_id, **kwargs)
530
531    def get_user_stream(
532        self, user_id: int, **kwargs
533    ) -> Generator[StreamItem, None, None]:
534        """
535        Returns generator of track uploaded by given user and
536        reposts by this user
537        """
538        return UserStreamRequest(self, user_id=user_id, **kwargs)
539
540    def get_user_tracks(
541        self, user_id: int, **kwargs
542    ) -> Generator[BasicTrack, None, None]:
543        """
544        Get tracks uploaded by this user
545        """
546        return UserTracksRequest(self, user_id=user_id, **kwargs)
547
548    def get_user_popular_tracks(
549        self, user_id: int, **kwargs
550    ) -> Generator[BasicTrack, None, None]:
551        """
552        Get popular tracks uploaded by this user
553        """
554        return UserToptracksRequest(self, user_id=user_id, **kwargs)
555
556    def get_user_albums(
557        self, user_id: int, **kwargs
558    ) -> Generator[BasicAlbumPlaylist, None, None]:
559        """
560        Get albums uploaded by this user
561        """
562        return UserAlbumsRequest(self, user_id=user_id, **kwargs)
563
564    def get_user_playlists(
565        self, user_id: int, **kwargs
566    ) -> Generator[BasicAlbumPlaylist, None, None]:
567        """
568        Get playlists uploaded by this user
569        """
570        return UserPlaylistsRequest(self, user_id=user_id, **kwargs)
571
572    def get_user_links(self, user_urn: str, **kwargs) -> List[WebProfile]:
573        """
574        Get links in this user's description
575        """
576        return UserWebProfilesRequest(self, user_urn=user_urn, **kwargs)

SoundCloud v2 API client

SoundCloud( client_id: Optional[str] = None, auth_token: Optional[str] = None, user_agent: str = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:93.0) Gecko/20100101 Firefox/93.0', impersonate: Literal['edge99', 'edge101', 'chrome99', 'chrome100', 'chrome101', 'chrome104', 'chrome107', 'chrome110', 'chrome116', 'chrome119', 'chrome120', 'chrome123', 'chrome124', 'chrome131', 'chrome133a', 'chrome136', 'chrome142', 'chrome145', 'chrome146', 'chrome99_android', 'chrome131_android', 'safari153', 'safari155', 'safari170', 'safari172_ios', 'safari180', 'safari180_ios', 'safari184', 'safari184_ios', 'safari260', 'safari2601', 'safari260_ios', 'firefox133', 'firefox135', 'firefox144', 'firefox147', 'tor145', 'chrome', 'edge', 'safari', 'safari_ios', 'safari_beta', 'safari_ios_beta', 'chrome_android', 'firefox', 'safari15_3', 'safari15_5', 'safari17_0', 'safari17_2_ios', 'safari18_0', 'safari18_0_ios', 'safari18_4', 'safari18_4_ios'] = 'chrome')
 89    def __init__(
 90        self,
 91        client_id: Optional[str] = None,
 92        auth_token: Optional[str] = None,
 93        user_agent: str = _DEFAULT_USER_AGENT,
 94        impersonate: BrowserTypeLiteral = "chrome",
 95    ) -> None:
 96        self._impersonate = impersonate
 97        self._session: requests.Session = requests.Session(impersonate=impersonate)
 98        if not client_id:
 99            client_id = self.generate_client_id(impersonate=impersonate)
100
101        self.client_id = client_id
102        self._user_agent = user_agent
103        self._auth_token = None
104        self._authorization = None
105        self.auth_token = auth_token
client_id: str

SoundCloud client ID. Needed for all requests.

auth_token: Optional[str]
107    @property
108    def auth_token(self) -> Optional[str]:
109        """SoundCloud auth token. Only needed for some requests."""
110        return self._auth_token

SoundCloud auth token. Only needed for some requests.

@classmethod
def generate_client_id( cls, impersonate: Literal['edge99', 'edge101', 'chrome99', 'chrome100', 'chrome101', 'chrome104', 'chrome107', 'chrome110', 'chrome116', 'chrome119', 'chrome120', 'chrome123', 'chrome124', 'chrome131', 'chrome133a', 'chrome136', 'chrome142', 'chrome145', 'chrome146', 'chrome99_android', 'chrome131_android', 'safari153', 'safari155', 'safari170', 'safari172_ios', 'safari180', 'safari180_ios', 'safari184', 'safari184_ios', 'safari260', 'safari2601', 'safari260_ios', 'firefox133', 'firefox135', 'firefox144', 'firefox147', 'tor145', 'chrome', 'edge', 'safari', 'safari_ios', 'safari_beta', 'safari_ios_beta', 'chrome_android', 'firefox', 'safari15_3', 'safari15_5', 'safari17_0', 'safari17_2_ios', 'safari18_0', 'safari18_0_ios', 'safari18_4', 'safari18_4_ios'] = 'chrome') -> str:
127    @classmethod
128    def generate_client_id(cls, impersonate: BrowserTypeLiteral = "chrome") -> str:
129        """Generates a SoundCloud client ID
130
131        Raises:
132            ClientIDGenerationError: Client ID could not be generated.
133
134        Returns:
135            str: Valid client ID
136        """
137        with requests.Session(impersonate=impersonate) as s:
138            r = s.get("https://soundcloud.com")
139            r.raise_for_status()
140            matches = cls._ASSETS_SCRIPTS_REGEX.findall(r.text)
141            if not matches:
142                raise ClientIDGenerationError("No asset scripts found")
143            for url in matches:
144                r = s.get(url)
145                r.raise_for_status()
146                client_id = cls._CLIENT_ID_REGEX.search(r.text)
147                if client_id:
148                    return client_id.group(1)
149            raise ClientIDGenerationError(f"Could not find client_id in script '{url}'")

Generates a SoundCloud client ID

Raises:
  • ClientIDGenerationError: Client ID could not be generated.
Returns:

str: Valid client ID

def is_client_id_valid(self) -> bool:
151    def is_client_id_valid(self) -> bool:
152        """
153        Checks if current client_id is valid
154        """
155        try:
156            TrackRequest(self, track_id=1032303631, use_auth=False)
157            return True
158        except HTTPError as err:
159            if err.response.status_code == 401:
160                return False
161            else:
162                raise

Checks if current client_id is valid

def is_auth_token_valid(self) -> bool:
164    def is_auth_token_valid(self) -> bool:
165        """
166        Checks if current auth_token is valid
167        """
168        try:
169            MeRequest(self)
170            return True
171        except HTTPError as err:
172            if err.response.status_code == 401:
173                return False
174            else:
175                raise

Checks if current auth_token is valid

def get_me(self) -> Optional[User]:
177    def get_me(self) -> Optional[User]:
178        """
179        Gets the user associated with client's auth token
180        """
181        return MeRequest(self)

Gets the user associated with client's auth token

def get_my_history( self, **kwargs) -> Generator[HistoryItem, NoneType, NoneType]:
183    def get_my_history(self, **kwargs) -> Generator[HistoryItem, None, None]:
184        """
185        Returns the stream of recently listened tracks
186        for the client's auth token
187        """
188        return MeHistoryRequest(self, **kwargs)

Returns the stream of recently listened tracks for the client's auth token

def get_my_stream( self, **kwargs) -> Generator[Union[TrackStreamItem, PlaylistStreamItem, TrackStreamRepostItem, PlaylistStreamRepostItem], NoneType, NoneType]:
190    def get_my_stream(self, **kwargs) -> Generator[StreamItem, None, None]:
191        """
192        Returns the stream of recent uploads/reposts
193        for the client's auth token
194        """
195        return MeStreamRequest(self, **kwargs)

Returns the stream of recent uploads/reposts for the client's auth token

def resolve( self, url: str) -> Union[User, Track, AlbumPlaylist, NoneType]:
197    def resolve(self, url: str) -> Optional[SearchItem]:
198        """
199        Returns the resource at the given URL if it
200        exists, otherwise return None
201        """
202        return ResolveRequest(self, url=url)

Returns the resource at the given URL if it exists, otherwise return None

def search( self, query: str, **kwargs) -> Generator[Union[User, Track, AlbumPlaylist], NoneType, NoneType]:
204    def search(self, query: str, **kwargs) -> Generator[SearchItem, None, None]:
205        """
206        Search for users, tracks, and playlists
207        """
208        return SearchRequest(self, q=query, **kwargs)

Search for users, tracks, and playlists

def search_albums( self, query: str, **kwargs) -> Generator[AlbumPlaylist, NoneType, NoneType]:
210    def search_albums(
211        self, query: str, **kwargs
212    ) -> Generator[AlbumPlaylist, None, None]:
213        """
214        Search for albums (not playlists)
215        """
216        return SearchAlbumsRequest(self, q=query, **kwargs)

Search for albums (not playlists)

def search_playlists( self, query: str, **kwargs) -> Generator[AlbumPlaylist, NoneType, NoneType]:
218    def search_playlists(
219        self, query: str, **kwargs
220    ) -> Generator[AlbumPlaylist, None, None]:
221        """
222        Search for playlists
223        """
224        return SearchPlaylistsRequest(self, q=query, **kwargs)

Search for playlists

def search_tracks( self, query: str, **kwargs) -> Generator[Track, NoneType, NoneType]:
226    def search_tracks(self, query: str, **kwargs) -> Generator[Track, None, None]:
227        """
228        Search for tracks
229        """
230        return SearchTracksRequest(self, q=query, **kwargs)

Search for tracks

def search_users( self, query: str, **kwargs) -> Generator[User, NoneType, NoneType]:
232    def search_users(self, query: str, **kwargs) -> Generator[User, None, None]:
233        """
234        Search for users
235        """
236        return SearchUsersRequest(self, q=query, **kwargs)

Search for users

def get_tag_tracks_recent( self, tag: str, **kwargs) -> Generator[Track, NoneType, NoneType]:
238    def get_tag_tracks_recent(self, tag: str, **kwargs) -> Generator[Track, None, None]:
239        """
240        Get most recent tracks for this tag
241        """
242        return TagRecentTracksRequest(self, tag=tag, **kwargs)

Get most recent tracks for this tag

def get_playlist( self, playlist_id: int) -> Optional[BasicAlbumPlaylist]:
244    def get_playlist(self, playlist_id: int) -> Optional[BasicAlbumPlaylist]:
245        """
246        Returns the playlist with the given playlist_id.
247        If the ID is invalid, return None
248        """
249        return PlaylistRequest(self, playlist_id=playlist_id)

Returns the playlist with the given playlist_id. If the ID is invalid, return None

def post_playlist( self, sharing: Literal['private', 'public'], title: str, tracks: List[int]) -> Optional[BasicAlbumPlaylist]:
251    def post_playlist(
252        self, sharing: Literal["private", "public"], title: str, tracks: List[int]
253    ) -> Optional[BasicAlbumPlaylist]:
254        """
255        Create a new playlist
256        """
257        body = {"playlist": {"sharing": sharing, "title": title, "tracks": tracks}}
258        return PostPlaylistRequest(self, body=body)

Create a new playlist

def delete_playlist( self, playlist_id: int) -> Optional[NoContentResponse]:
260    def delete_playlist(self, playlist_id: int) -> Optional[NoContentResponse]:
261        """
262        Delete a playlist
263        """
264        return DeletePlaylistRequest(self, playlist_id=playlist_id)

Delete a playlist

def get_playlist_likers( self, playlist_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
266    def get_playlist_likers(
267        self, playlist_id: int, **kwargs
268    ) -> Generator[User, None, None]:
269        """
270        Get people who liked this playlist
271        """
272        return PlaylistLikersRequest(self, playlist_id=playlist_id, **kwargs)

Get people who liked this playlist

def get_playlist_reposters( self, playlist_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
274    def get_playlist_reposters(
275        self, playlist_id: int, **kwargs
276    ) -> Generator[User, None, None]:
277        """
278        Get people who reposted this playlist
279        """
280        return PlaylistRepostersRequest(self, playlist_id=playlist_id, **kwargs)

Get people who reposted this playlist

def get_track(self, track_id: int) -> Optional[BasicTrack]:
282    def get_track(self, track_id: int) -> Optional[BasicTrack]:
283        """
284        Returns the track with the given track_id.
285        If the ID is invalid, return None
286        """
287        return TrackRequest(self, track_id=track_id)

Returns the track with the given track_id. If the ID is invalid, return None

def get_tracks( self, track_ids: List[int], playlistId: Optional[int] = None, playlistSecretToken: Optional[str] = None, **kwargs) -> List[BasicTrack]:
289    def get_tracks(
290        self,
291        track_ids: List[int],
292        playlistId: Optional[int] = None,
293        playlistSecretToken: Optional[str] = None,
294        **kwargs,
295    ) -> List[BasicTrack]:
296        """
297        Returns the tracks with the given track_ids.
298        Can be used to get track info for hidden tracks in a hidden playlist.
299        """
300        if playlistId is not None:
301            kwargs["playlistId"] = playlistId
302        if playlistSecretToken is not None:
303            kwargs["playlistSecretToken"] = playlistSecretToken
304        return TracksRequest(
305            self, ids=",".join([str(id) for id in track_ids]), **kwargs
306        )

Returns the tracks with the given track_ids. Can be used to get track info for hidden tracks in a hidden playlist.

def get_track_albums( self, track_id: int, **kwargs) -> Generator[BasicAlbumPlaylist, NoneType, NoneType]:
308    def get_track_albums(
309        self, track_id: int, **kwargs
310    ) -> Generator[BasicAlbumPlaylist, None, None]:
311        """
312        Get albums that this track is in
313        """
314        return TrackAlbumsRequest(self, track_id=track_id, **kwargs)

Get albums that this track is in

def get_track_playlists( self, track_id: int, **kwargs) -> Generator[BasicAlbumPlaylist, NoneType, NoneType]:
316    def get_track_playlists(
317        self, track_id: int, **kwargs
318    ) -> Generator[BasicAlbumPlaylist, None, None]:
319        """
320        Get playlists that this track is in
321        """
322        return TrackPlaylistsRequest(self, track_id=track_id, **kwargs)

Get playlists that this track is in

def get_track_comments( self, track_id: int, threaded: int = 0, **kwargs) -> Generator[BasicComment, NoneType, NoneType]:
324    def get_track_comments(
325        self, track_id: int, threaded: int = 0, **kwargs
326    ) -> Generator[BasicComment, None, None]:
327        """
328        Get comments on this track
329        """
330        return TrackCommentsRequest(
331            self, track_id=track_id, threaded=threaded, **kwargs
332        )

Get comments on this track

def get_track_comments_with_interactions( self, track_id: int, threaded: int = 0, **kwargs) -> Generator[CommentWithInteractions, NoneType, NoneType]:
334    def get_track_comments_with_interactions(
335        self, track_id: int, threaded: int = 0, **kwargs
336    ) -> Generator[CommentWithInteractions, None, None]:
337        """
338        Get comments on this track with interaction data. Requires authentication.
339        """
340        track = self.get_track(track_id)
341        if not track:
342            return
343        track_urn = track.urn
344        creator_urn = track.user.urn
345        comments = self.get_track_comments(track_id, threaded, **kwargs)
346        while True:
347            chunk = list(itertools.islice(comments, 10))
348            if not chunk:
349                return
350            comment_urns = [comment.self.urn for comment in chunk]
351            result = UserInteractionsRequest(
352                self,
353                UserInteractionsQueryParams(
354                    creator_urn,
355                    "sc:interactiontype:reaction",
356                    track_urn,
357                    comment_urns,
358                ),
359            )
360            if not result:
361                return
362            comments_with_interactions = []
363            for comment, user_interactions, creator_interactions in zip(
364                chunk, result.user, result.creator
365            ):
366                assert user_interactions.interactionCounts is not None
367                likes = list(
368                    filter(
369                        lambda x: (
370                            x.interactionTypeValueUrn == "sc:interactiontypevalue:like"
371                        ),
372                        user_interactions.interactionCounts,
373                    )
374                )
375                num_likes = likes[0].count if likes else 0
376                comments_with_interactions.append(
377                    CommentWithInteractions(
378                        comment=comment,
379                        likes=num_likes or 0,
380                        liked_by_creator=creator_interactions.userInteraction
381                        == "sc:interactiontypevalue:like",
382                        liked_by_user=user_interactions.userInteraction
383                        == "sc:interactiontypevalue:like",
384                    )
385                )
386            yield from comments_with_interactions

Get comments on this track with interaction data. Requires authentication.

def get_track_likers( self, track_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
388    def get_track_likers(self, track_id: int, **kwargs) -> Generator[User, None, None]:
389        """
390        Get users who liked this track
391        """
392        return TrackLikersRequest(self, track_id=track_id, **kwargs)

Get users who liked this track

def get_track_reposters( self, track_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
402    def get_track_reposters(
403        self, track_id: int, **kwargs
404    ) -> Generator[User, None, None]:
405        """
406        Get users who reposted this track
407        """
408        return TrackRepostersRequest(self, track_id=track_id, **kwargs)

Get users who reposted this track

def get_track_original_download(self, track_id: int, token: Optional[str] = None) -> Optional[str]:
410    def get_track_original_download(
411        self, track_id: int, token: Optional[str] = None
412    ) -> Optional[str]:
413        """
414        Get track original download link. If track is private,
415        requires secret token to be provided (last part of secret URL).
416        Requires authentication.
417        """
418        if token is not None:
419            download = TrackOriginalDownloadRequest(
420                self, track_id=track_id, secret_token=token
421            )
422        else:
423            download = TrackOriginalDownloadRequest(self, track_id=track_id)
424        if download is None:
425            return None
426        else:
427            return download.redirectUri

Get track original download link. If track is private, requires secret token to be provided (last part of secret URL). Requires authentication.

def get_user(self, user_id: int) -> Optional[User]:
429    def get_user(self, user_id: int) -> Optional[User]:
430        """
431        Returns the user with the given user_id.
432        If the ID is invalid, return None
433        """
434        return UserRequest(self, user_id=user_id)

Returns the user with the given user_id. If the ID is invalid, return None

def get_user_by_username(self, username: str) -> Optional[User]:
436    def get_user_by_username(self, username: str) -> Optional[User]:
437        """
438        Returns the user with the given username.
439        If the username is invalid, return None
440        """
441        resource = self.resolve(f"https://soundcloud.com/{username}")
442        if resource and isinstance(resource, User):
443            return resource
444        else:
445            return None

Returns the user with the given username. If the username is invalid, return None

def get_user_comments( self, user_id: int, **kwargs) -> Generator[Comment, NoneType, NoneType]:
447    def get_user_comments(
448        self, user_id: int, **kwargs
449    ) -> Generator[Comment, None, None]:
450        """
451        Get comments by this user
452        """
453        return UserCommentsRequest(self, user_id=user_id, **kwargs)

Get comments by this user

def get_conversation_messages( self, user_id: int, conversation_id: int, **kwargs) -> Generator[Message, NoneType, NoneType]:
455    def get_conversation_messages(
456        self, user_id: int, conversation_id: int, **kwargs
457    ) -> Generator[Message, None, None]:
458        """
459        Get messages in this conversation
460        """
461        return UserConversationMessagesRequest(
462            self, user_id=user_id, conversation_id=conversation_id, **kwargs
463        )

Get messages in this conversation

def get_conversations( self, user_id: int, **kwargs) -> Generator[Conversation, NoneType, NoneType]:
465    def get_conversations(
466        self, user_id: int, **kwargs
467    ) -> Generator[Conversation, None, None]:
468        """
469        Get conversations including this user
470        """
471        return UserConversationsRequest(self, user_id=user_id, **kwargs)

Get conversations including this user

def get_unread_conversations( self, user_id: int, **kwargs) -> Generator[Conversation, NoneType, NoneType]:
473    def get_unread_conversations(
474        self, user_id: int, **kwargs
475    ) -> Generator[Conversation, None, None]:
476        """
477        Get conversations unread by this user
478        """
479        return UserConversationsUnreadRequest(self, user_id=user_id, **kwargs)

Get conversations unread by this user

def get_user_emails( self, user_id: int, **kwargs) -> Generator[UserEmail, NoneType, NoneType]:
481    def get_user_emails(
482        self, user_id: int, **kwargs
483    ) -> Generator[UserEmail, None, None]:
484        """
485        Get user's email addresses. Requires authentication.
486        """
487        return UserEmailsRequest(self, user_id=user_id, **kwargs)

Get user's email addresses. Requires authentication.

def get_user_followers( self, user_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
497    def get_user_followers(self, user_id: int, **kwargs) -> Generator[User, None, None]:
498        """
499        Get user's followers
500        """
501        return UserFollowersRequest(self, user_id=user_id, **kwargs)

Get user's followers

def get_user_following( self, user_id: int, **kwargs) -> Generator[User, NoneType, NoneType]:
503    def get_user_following(self, user_id: int, **kwargs) -> Generator[User, None, None]:
504        """
505        Get users this user is following
506        """
507        return UserFollowingsRequest(self, user_id=user_id, **kwargs)

Get users this user is following

def get_user_likes( self, user_id: int, **kwargs) -> Generator[Union[TrackLike, PlaylistLike], NoneType, NoneType]:
509    def get_user_likes(self, user_id: int, **kwargs) -> Generator[Like, None, None]:
510        """
511        Get likes by this user
512        """
513        return UserLikesRequest(self, user_id=user_id, **kwargs)

Get likes by this user

def get_user_reposts( self, user_id: int, **kwargs) -> Generator[Union[TrackStreamRepostItem, PlaylistStreamRepostItem], NoneType, NoneType]:
523    def get_user_reposts(
524        self, user_id: int, **kwargs
525    ) -> Generator[RepostItem, None, None]:
526        """
527        Get reposts by this user
528        """
529        return UserRepostsRequest(self, user_id=user_id, **kwargs)

Get reposts by this user

def get_user_stream( self, user_id: int, **kwargs) -> Generator[Union[TrackStreamItem, PlaylistStreamItem, TrackStreamRepostItem, PlaylistStreamRepostItem], NoneType, NoneType]:
531    def get_user_stream(
532        self, user_id: int, **kwargs
533    ) -> Generator[StreamItem, None, None]:
534        """
535        Returns generator of track uploaded by given user and
536        reposts by this user
537        """
538        return UserStreamRequest(self, user_id=user_id, **kwargs)

Returns generator of track uploaded by given user and reposts by this user

def get_user_tracks( self, user_id: int, **kwargs) -> Generator[BasicTrack, NoneType, NoneType]:
540    def get_user_tracks(
541        self, user_id: int, **kwargs
542    ) -> Generator[BasicTrack, None, None]:
543        """
544        Get tracks uploaded by this user
545        """
546        return UserTracksRequest(self, user_id=user_id, **kwargs)

Get tracks uploaded by this user

def get_user_albums( self, user_id: int, **kwargs) -> Generator[BasicAlbumPlaylist, NoneType, NoneType]:
556    def get_user_albums(
557        self, user_id: int, **kwargs
558    ) -> Generator[BasicAlbumPlaylist, None, None]:
559        """
560        Get albums uploaded by this user
561        """
562        return UserAlbumsRequest(self, user_id=user_id, **kwargs)

Get albums uploaded by this user

def get_user_playlists( self, user_id: int, **kwargs) -> Generator[BasicAlbumPlaylist, NoneType, NoneType]:
564    def get_user_playlists(
565        self, user_id: int, **kwargs
566    ) -> Generator[BasicAlbumPlaylist, None, None]:
567        """
568        Get playlists uploaded by this user
569        """
570        return UserPlaylistsRequest(self, user_id=user_id, **kwargs)

Get playlists uploaded by this user

class ClientIDGenerationError(builtins.Exception):
2class ClientIDGenerationError(Exception):
3    """
4    Raised when a client ID could not be dynamically generated.
5    """

Raised when a client ID could not be dynamically generated.

Like = typing.Union[TrackLike, PlaylistLike]
RepostItem = typing.Union[TrackStreamRepostItem, PlaylistStreamRepostItem]
SearchItem = typing.Union[User, Track, AlbumPlaylist]
@dataclass
class BasicComment(soundcloud.resource.base.BaseData):
16@dataclass
17class BasicComment(BaseData):
18    """Comment without a specified track"""
19
20    kind: str
21    id: int
22    body: str
23    created_at: datetime.datetime
24    timestamp: Optional[int]
25    track_id: int
26    user_id: int
27    self: CommentSelf
28    user: BasicUser

Comment without a specified track

BasicComment( kind: str, id: int, body: str, created_at: datetime.datetime, timestamp: Optional[int], track_id: int, user_id: int, self: CommentSelf, user: BasicUser)
kind: str
id: int
body: str
created_at: datetime.datetime
timestamp: Optional[int]
track_id: int
user_id: int
self: CommentSelf
user: BasicUser
@dataclass
class Comment(soundcloud.BasicComment):
31@dataclass
32class Comment(BasicComment):
33    """Comment with a specified track"""
34
35    track: CommentTrack

Comment with a specified track

Comment( kind: str, id: int, body: str, created_at: datetime.datetime, timestamp: Optional[int], track_id: int, user_id: int, self: CommentSelf, user: BasicUser, track: CommentTrack)
track: CommentTrack
@dataclass
class CommentWithInteractions(soundcloud.resource.base.BaseData):
25@dataclass
26class CommentWithInteractions(BaseData):
27    comment: BasicComment
28    likes: int
29    """Number of likes on comment"""
30
31    liked_by_creator: bool
32    """Whether comment was liked by the track creator"""
33
34    liked_by_user: bool
35    """Whether the current logged in user liked the comment"""
CommentWithInteractions( comment: BasicComment, likes: int, liked_by_creator: bool, liked_by_user: bool)
comment: BasicComment
likes: int

Number of likes on comment

liked_by_creator: bool

Whether comment was liked by the track creator

liked_by_user: bool

Whether the current logged in user liked the comment

@dataclass
class CommentSelf(soundcloud.resource.base.BaseData):
11@dataclass
12class CommentSelf(BaseData):
13    urn: str
CommentSelf(urn: str)
urn: str
@dataclass
class Conversation(soundcloud.resource.base.BaseData):
11@dataclass
12class Conversation(BaseData):
13    """DM conversation between two users"""
14
15    id: str
16    last_message: Message
17    read: bool
18    started_at: datetime.datetime
19    summary: str
20    users: Tuple[Union[BasicUser, MissingUser], ...]

DM conversation between two users

Conversation( id: str, last_message: Message, read: bool, started_at: datetime.datetime, summary: str, users: Tuple[Union[BasicUser, soundcloud.resource.user.MissingUser], ...])
id: str
last_message: Message
read: bool
started_at: datetime.datetime
summary: str
users: Tuple[Union[BasicUser, soundcloud.resource.user.MissingUser], ...]
@dataclass
class OriginalDownload(soundcloud.resource.base.BaseData):
 7@dataclass
 8class OriginalDownload(BaseData):
 9    """Contains a download link for a track"""
10
11    redirectUri: str

Contains a download link for a track

OriginalDownload(redirectUri: str)
redirectUri: str
@dataclass
class HistoryItem(soundcloud.resource.base.BaseData):
 8@dataclass
 9class HistoryItem(BaseData):
10    """Item in user's listen history"""
11
12    played_at: int
13    track: BasicTrack
14    track_id: int

Item in user's listen history

HistoryItem( played_at: int, track: BasicTrack, track_id: int)
played_at: int
track: BasicTrack
track_id: int
@dataclass
class PlaylistLike(soundcloud.resource.like.BaseLike):
23@dataclass
24class PlaylistLike(BaseLike):
25    """Like on a playlist"""
26
27    playlist: AlbumPlaylistNoTracks

Like on a playlist

PlaylistLike( created_at: datetime.datetime, kind: str, playlist: AlbumPlaylistNoTracks)
@dataclass
class TrackLike(soundcloud.resource.like.BaseLike):
16@dataclass
17class TrackLike(BaseLike):
18    """Like on a track"""
19
20    track: BasicTrack

Like on a track

TrackLike( created_at: datetime.datetime, kind: str, track: BasicTrack)
track: BasicTrack
@dataclass
class Message(soundcloud.resource.base.BaseData):
10@dataclass
11class Message(BaseData):
12    """Single DM between two users"""
13
14    content: str
15    conversation_id: str
16    sender: Union[BasicUser, MissingUser]
17    sender_urn: str
18    sender_type: str
19    sent_at: datetime.datetime

Single DM between two users

Message( content: str, conversation_id: str, sender: Union[BasicUser, soundcloud.resource.user.MissingUser], sender_urn: str, sender_type: str, sent_at: datetime.datetime)
content: str
conversation_id: str
sender: Union[BasicUser, soundcloud.resource.user.MissingUser]
sender_urn: str
sender_type: str
sent_at: datetime.datetime
@dataclass
class AlbumPlaylist(soundcloud.resource.playlist.BaseAlbumPlaylist):
22@dataclass
23class AlbumPlaylist(BaseAlbumPlaylist):
24    """Playlist or album with full user info"""
25
26    user: User

Playlist or album with full user info

AlbumPlaylist( artwork_url: Optional[str], created_at: datetime.datetime, description: Optional[str], duration: int, embeddable_by: str, genre: Optional[str], id: int, kind: str, label_name: Optional[str], last_modified: datetime.datetime, licence: Optional[str], likes_count: Optional[int], permalink: str, permalink_url: str, public: bool, purchase_title: Optional[str], purchase_url: Optional[str], release_date: Optional[str], reposts_count: Optional[int], secret_token: Optional[str], sharing: str, tag_list: str, title: str, uri: str, user_id: int, display_date: str, managed_by_feeds: bool, set_type: str, is_album: bool, published_at: Optional[datetime.datetime], track_count: int, tracks: Tuple[Union[BasicTrack, MiniTrack], ...], user: User)
user: User
@dataclass
class AlbumPlaylistNoTracks(soundcloud.resource.base.BaseData):
36@dataclass
37class AlbumPlaylistNoTracks(BaseData):
38    """Playlist or album with no track info"""
39
40    artwork_url: Optional[str]
41    created_at: datetime.datetime
42    duration: int
43    id: int
44    kind: str
45    last_modified: datetime.datetime
46    likes_count: Optional[int]
47    managed_by_feeds: bool
48    permalink: str
49    permalink_url: str
50    public: bool
51    reposts_count: Optional[int]
52    secret_token: Optional[str]
53    sharing: str
54    title: str
55    track_count: int
56    uri: str
57    user_id: int
58    set_type: str
59    is_album: bool
60    published_at: Optional[datetime.datetime]
61    release_date: Optional[str]
62    display_date: datetime.datetime
63    user: BasicUser

Playlist or album with no track info

AlbumPlaylistNoTracks( artwork_url: Optional[str], created_at: datetime.datetime, duration: int, id: int, kind: str, last_modified: datetime.datetime, likes_count: Optional[int], managed_by_feeds: bool, permalink: str, permalink_url: str, public: bool, reposts_count: Optional[int], secret_token: Optional[str], sharing: str, title: str, track_count: int, uri: str, user_id: int, set_type: str, is_album: bool, published_at: Optional[datetime.datetime], release_date: Optional[str], display_date: datetime.datetime, user: BasicUser)
artwork_url: Optional[str]
created_at: datetime.datetime
duration: int
id: int
kind: str
last_modified: datetime.datetime
likes_count: Optional[int]
managed_by_feeds: bool
public: bool
reposts_count: Optional[int]
secret_token: Optional[str]
sharing: str
title: str
track_count: int
uri: str
user_id: int
set_type: str
is_album: bool
published_at: Optional[datetime.datetime]
release_date: Optional[str]
display_date: datetime.datetime
user: BasicUser
@dataclass
class BasicAlbumPlaylist(soundcloud.resource.playlist.BaseAlbumPlaylist):
29@dataclass
30class BasicAlbumPlaylist(BaseAlbumPlaylist):
31    """Playlist or album with partial user info"""
32
33    user: BasicUser

Playlist or album with partial user info

BasicAlbumPlaylist( artwork_url: Optional[str], created_at: datetime.datetime, description: Optional[str], duration: int, embeddable_by: str, genre: Optional[str], id: int, kind: str, label_name: Optional[str], last_modified: datetime.datetime, licence: Optional[str], likes_count: Optional[int], permalink: str, permalink_url: str, public: bool, purchase_title: Optional[str], purchase_url: Optional[str], release_date: Optional[str], reposts_count: Optional[int], secret_token: Optional[str], sharing: str, tag_list: str, title: str, uri: str, user_id: int, display_date: str, managed_by_feeds: bool, set_type: str, is_album: bool, published_at: Optional[datetime.datetime], track_count: int, tracks: Tuple[Union[BasicTrack, MiniTrack], ...], user: BasicUser)
user: BasicUser
@dataclass
class PlaylistStreamItem(soundcloud.resource.stream.BaseStreamItem):
47@dataclass
48class PlaylistStreamItem(BaseStreamItem):
49    """Album or playlist post in user's feed"""
50
51    playlist: BasicAlbumPlaylist

Album or playlist post in user's feed

PlaylistStreamItem( created_at: datetime.datetime, type: str, user: BasicUser, uuid: str, caption: Optional[str], playlist: BasicAlbumPlaylist)
playlist: BasicAlbumPlaylist
@dataclass
class PlaylistStreamRepostItem(soundcloud.resource.stream.BaseStreamRepostItem):
54@dataclass
55class PlaylistStreamRepostItem(BaseStreamRepostItem):
56    """Album or playlist repost in user's feed"""
57
58    playlist: BasicAlbumPlaylist

Album or playlist repost in user's feed

PlaylistStreamRepostItem( created_at: datetime.datetime, type: str, user: BasicUser, uuid: str, caption: Optional[str], reposted: Optional[soundcloud.resource.stream.Reposted], playlist: BasicAlbumPlaylist)
playlist: BasicAlbumPlaylist
@dataclass
class TrackStreamItem(soundcloud.resource.stream.BaseStreamItem):
33@dataclass
34class TrackStreamItem(BaseStreamItem):
35    """Track post in user's feed"""
36
37    track: BasicTrack

Track post in user's feed

TrackStreamItem( created_at: datetime.datetime, type: str, user: BasicUser, uuid: str, caption: Optional[str], track: BasicTrack)
track: BasicTrack
@dataclass
class TrackStreamRepostItem(soundcloud.resource.stream.BaseStreamRepostItem):
40@dataclass
41class TrackStreamRepostItem(BaseStreamRepostItem):
42    """Track repost in user's feed"""
43
44    track: BasicTrack

Track repost in user's feed

TrackStreamRepostItem( created_at: datetime.datetime, type: str, user: BasicUser, uuid: str, caption: Optional[str], reposted: Optional[soundcloud.resource.stream.Reposted], track: BasicTrack)
track: BasicTrack
@dataclass
class BasicTrack(soundcloud.resource.track.BaseTrack):
80@dataclass
81class BasicTrack(BaseTrack):
82    """Track with partial user info"""
83
84    user: BasicUser

Track with partial user info

BasicTrack( artwork_url: Optional[str], created_at: datetime.datetime, description: Optional[str], duration: int, embeddable_by: str, genre: Optional[str], id: int, kind: str, label_name: Optional[str], last_modified: datetime.datetime, licence: Optional[str], likes_count: Optional[int], permalink: str, permalink_url: str, public: bool, purchase_title: Optional[str], purchase_url: Optional[str], release_date: Optional[str], reposts_count: Optional[int], secret_token: Optional[str], sharing: str, tag_list: str, title: str, uri: str, user_id: int, display_date: str, caption: Optional[str], commentable: bool, comment_count: Optional[int], downloadable: bool, download_count: Optional[int], full_duration: int, has_downloads_left: bool, playback_count: Optional[int], state: str, streamable: bool, urn: str, visuals: Optional[Visuals], waveform_url: str, media: Media, station_urn: Optional[str], station_permalink: Optional[str], track_authorization: str, monetization_model: str, policy: str, user: BasicUser)
user: BasicUser
@dataclass
class Format(soundcloud.resource.base.BaseData):
12@dataclass
13class Format(BaseData):
14    """Track file format"""
15
16    protocol: str
17    mime_type: str

Track file format

Format(protocol: str, mime_type: str)
protocol: str
mime_type: str
@dataclass
class Media(soundcloud.resource.base.BaseData):
32@dataclass
33class Media(BaseData):
34    """List of available transcodings"""
35
36    transcodings: Tuple[Transcoding, ...]

List of available transcodings

Media(transcodings: Tuple[Transcoding, ...])
transcodings: Tuple[Transcoding, ...]
@dataclass
class MiniTrack(soundcloud.resource.base.BaseData):
87@dataclass
88class MiniTrack(BaseData):
89    """Track with minimal info"""
90
91    id: int
92    kind: str
93    monetization_model: str
94    policy: str

Track with minimal info

MiniTrack(id: int, kind: str, monetization_model: str, policy: str)
id: int
kind: str
monetization_model: str
policy: str
@dataclass
class PublisherMetadata(soundcloud.resource.base.BaseData):
39@dataclass
40class PublisherMetadata(BaseData):
41    """Publisher info"""
42
43    id: str
44    urn: str
45    contains_music: bool

Publisher info

PublisherMetadata(id: str, urn: str, contains_music: bool)
id: str
urn: str
contains_music: bool
@dataclass
class Track(soundcloud.resource.track.BaseTrack):
73@dataclass
74class Track(BaseTrack):
75    """Track with full user info"""
76
77    user: User

Track with full user info

Track( artwork_url: Optional[str], created_at: datetime.datetime, description: Optional[str], duration: int, embeddable_by: str, genre: Optional[str], id: int, kind: str, label_name: Optional[str], last_modified: datetime.datetime, licence: Optional[str], likes_count: Optional[int], permalink: str, permalink_url: str, public: bool, purchase_title: Optional[str], purchase_url: Optional[str], release_date: Optional[str], reposts_count: Optional[int], secret_token: Optional[str], sharing: str, tag_list: str, title: str, uri: str, user_id: int, display_date: str, caption: Optional[str], commentable: bool, comment_count: Optional[int], downloadable: bool, download_count: Optional[int], full_duration: int, has_downloads_left: bool, playback_count: Optional[int], state: str, streamable: bool, urn: str, visuals: Optional[Visuals], waveform_url: str, media: Media, station_urn: Optional[str], station_permalink: Optional[str], track_authorization: str, monetization_model: str, policy: str, user: User)
user: User
@dataclass
class Transcoding(soundcloud.resource.base.BaseData):
20@dataclass
21class Transcoding(BaseData):
22    """Available transcoding for track"""
23
24    url: str
25    preset: str
26    duration: int
27    snipped: bool
28    format: Format
29    quality: str

Available transcoding for track

Transcoding( url: str, preset: str, duration: int, snipped: bool, format: Format, quality: str)
url: str
preset: str
duration: int
snipped: bool
format: Format
quality: str
@dataclass
class CommentTrack(soundcloud.resource.base.BaseData):
 97@dataclass
 98class CommentTrack(BaseData):
 99    """Track with partial info"""
100
101    artwork_url: Optional[str]
102    caption: Optional[str]
103    id: int
104    kind: str
105    last_modified: datetime.datetime
106    permalink: str
107    permalink_url: str
108    public: bool
109    secret_token: Optional[str]
110    sharing: str
111    title: str
112    uri: str
113    urn: str
114    user_id: int
115    full_duration: int
116    duration: int
117    display_date: datetime.datetime
118    media: Media
119    station_urn: Optional[str]
120    station_permalink: Optional[str]
121    track_authorization: str
122    monetization_model: str
123    policy: str
124    user: BasicUser

Track with partial info

CommentTrack( artwork_url: Optional[str], caption: Optional[str], id: int, kind: str, last_modified: datetime.datetime, permalink: str, permalink_url: str, public: bool, secret_token: Optional[str], sharing: str, title: str, uri: str, urn: str, user_id: int, full_duration: int, duration: int, display_date: datetime.datetime, media: Media, station_urn: Optional[str], station_permalink: Optional[str], track_authorization: str, monetization_model: str, policy: str, user: BasicUser)
artwork_url: Optional[str]
caption: Optional[str]
id: int
kind: str
last_modified: datetime.datetime
public: bool
secret_token: Optional[str]
sharing: str
title: str
uri: str
urn: str
user_id: int
full_duration: int
duration: int
display_date: datetime.datetime
media: Media
station_urn: Optional[str]
track_authorization: str
monetization_model: str
policy: str
user: BasicUser
@dataclass
class Badges(soundcloud.resource.base.BaseData):
20@dataclass
21class Badges(BaseData):
22    """User badges"""
23
24    pro: bool
25    pro_unlimited: bool
26    verified: bool

User badges

Badges(pro: bool, pro_unlimited: bool, verified: bool)
pro: bool
pro_unlimited: bool
verified: bool
@dataclass
class BasicUser(soundcloud.resource.base.BaseData):
29@dataclass
30class BasicUser(BaseData):
31    """User with partial information"""
32
33    avatar_url: str
34    first_name: str
35    followers_count: int
36    full_name: str
37    id: int
38    kind: str
39    last_modified: datetime.datetime
40    last_name: str
41    permalink: str
42    permalink_url: str
43    uri: str
44    urn: str
45    username: str
46    verified: bool
47    city: Optional[str]
48    country_code: Optional[str]
49    badges: Badges
50    station_urn: Optional[str]
51    station_permalink: Optional[str]

User with partial information

BasicUser( avatar_url: str, first_name: str, followers_count: int, full_name: str, id: int, kind: str, last_modified: datetime.datetime, last_name: str, permalink: str, permalink_url: str, uri: str, urn: str, username: str, verified: bool, city: Optional[str], country_code: Optional[str], badges: Badges, station_urn: Optional[str], station_permalink: Optional[str])
avatar_url: str
first_name: str
followers_count: int
full_name: str
id: int
kind: str
last_modified: datetime.datetime
last_name: str
uri: str
urn: str
username: str
verified: bool
city: Optional[str]
country_code: Optional[str]
badges: Badges
station_urn: Optional[str]
@dataclass
class CreatorSubscription(soundcloud.resource.base.BaseData):
15@dataclass
16class CreatorSubscription(BaseData):
17    product: Product
CreatorSubscription(product: Product)
product: Product
@dataclass
class Product(soundcloud.resource.base.BaseData):
10@dataclass
11class Product(BaseData):
12    id: str
Product(id: str)
id: str
@dataclass
class User(soundcloud.BasicUser):
54@dataclass
55class User(BasicUser):
56    """User with full information"""
57
58    comments_count: int
59    created_at: Optional[datetime.datetime]
60    creator_subscriptions: Tuple[CreatorSubscription, ...]
61    creator_subscription: CreatorSubscription
62    description: Optional[str]
63    followings_count: int
64    groups_count: int
65    likes_count: Optional[int]
66    playlist_likes_count: Optional[int]
67    playlist_count: int
68    reposts_count: Optional[int]
69    track_count: int
70    visuals: Optional[Visuals]

User with full information

User( avatar_url: str, first_name: str, followers_count: int, full_name: str, id: int, kind: str, last_modified: datetime.datetime, last_name: str, permalink: str, permalink_url: str, uri: str, urn: str, username: str, verified: bool, city: Optional[str], country_code: Optional[str], badges: Badges, station_urn: Optional[str], station_permalink: Optional[str], comments_count: int, created_at: Optional[datetime.datetime], creator_subscriptions: Tuple[CreatorSubscription, ...], creator_subscription: CreatorSubscription, description: Optional[str], followings_count: int, groups_count: int, likes_count: Optional[int], playlist_likes_count: Optional[int], playlist_count: int, reposts_count: Optional[int], track_count: int, visuals: Optional[Visuals])
comments_count: int
created_at: Optional[datetime.datetime]
creator_subscriptions: Tuple[CreatorSubscription, ...]
creator_subscription: CreatorSubscription
description: Optional[str]
followings_count: int
groups_count: int
likes_count: Optional[int]
playlist_likes_count: Optional[int]
playlist_count: int
reposts_count: Optional[int]
track_count: int
visuals: Optional[Visuals]
@dataclass
class UserEmail(soundcloud.resource.base.BaseData):
87@dataclass
88class UserEmail(BaseData):
89    """Email address associated with a user"""
90
91    address: str
92    confirmed: bool
93    id: int
94    kind: str
95    last_modified: datetime.datetime
96    primary: bool
97    urn: str
98    user_id: str

Email address associated with a user

UserEmail( address: str, confirmed: bool, id: int, kind: str, last_modified: datetime.datetime, primary: bool, urn: str, user_id: str)
address: str
confirmed: bool
id: int
kind: str
last_modified: datetime.datetime
primary: bool
urn: str
user_id: str
@dataclass
class Visual(soundcloud.resource.base.BaseData):
 8@dataclass
 9class Visual(BaseData):
10    urn: str
11    entry_time: int
12    visual_url: str
Visual(urn: str, entry_time: int, visual_url: str)
urn: str
entry_time: int
visual_url: str
@dataclass
class Visuals(soundcloud.resource.base.BaseData):
15@dataclass
16class Visuals(BaseData):
17    urn: str
18    enabled: bool
19    visuals: Tuple[Visual, ...]
Visuals( urn: str, enabled: bool, visuals: Tuple[Visual, ...])
urn: str
enabled: bool
visuals: Tuple[Visual, ...]
@dataclass
class WebProfile(soundcloud.resource.base.BaseData):
 8@dataclass
 9class WebProfile(BaseData):
10    url: str
11    network: str
12    title: str
13    username: Optional[str]
WebProfile(url: str, network: str, title: str, username: Optional[str])
url: str
network: str
title: str
username: Optional[str]
@dataclass
class NoContentResponse(soundcloud.resource.base.BaseData):
 7@dataclass
 8class NoContentResponse(BaseData):
 9    """Response with no content, mainly for DELETE requests"""
10
11    status_code: int

Response with no content, mainly for DELETE requests

NoContentResponse(status_code: int)
status_code: int