Skip to content

Commit

Permalink
Merge pull request #1 from robsonke/main
Browse files Browse the repository at this point in the history
Several small improvements
  • Loading branch information
robsonke authored Jan 8, 2025
2 parents 987eaab + bd572bf commit 813bdd6
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 25 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ repos:
types: [python]
entry: scripts/run-in-env.sh ruff check --fix
require_serial: true
stages: [commit, push, manual]
stages: [pre-commit, pre-push, manual]
- id: ruff-format
name: 🐶 Ruff Formatter
language: system
types: [python]
entry: scripts/run-in-env.sh ruff format
require_serial: true
stages: [commit, push, manual]
stages: [pre-commit, pre-push, manual]
- id: check-ast
name: 🐍 Check Python AST
language: system
Expand All @@ -36,7 +36,7 @@ repos:
language: system
types: [text, executable]
entry: scripts/run-in-env.sh check-executables-have-shebangs
stages: [commit, push, manual]
stages: [pre-commit, pre-push, manual]
# - id: check-merge-conflict
# name: 💥 Check for merge conflicts
# language: system
Expand Down
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,22 @@ The package is published on PyPI and can be installed by running:
pip install soundcloudpy
```

## How to get O-Auth and Client id
## How to get OAuth and Client id

1. Go to [soundcloud](https://soundcloud.com) and login in
2. Open the "Inspect" tool (F12 on most browsers)
3. Refresh the page
4. Go to the page "Network" on the inspect terminal
5. Search on the column "File" for the "client_id" and "Request headers" for "Authorization"
5. Search on the column "File" for the "client_id" and the "oauth_token" cookie for "Authorization"

`client_id`: string of 32 bytes alphanumeric

`authorization`: string that begins with O-Auth and a string (the o-auth token is "O-Auth . . .")
`authorization`: string that begins with OAuth and a string (the o-auth token is "OAuth . . .")

Example (O-Auth and client_id are NOT real, use yours):
Example (OAuth and client_id are NOT real, use yours):

```
python -m example --client_id jHvc9wa0Ejf092wj3f3920w3F920as02 --auth_token 'O-Auth 3-26432-21446-asdif2309fj'
python -m example --client_id jHvc9wa0Ejf092wj3f3920w3F920as02 --auth_token 'OAuth 3-26432-21446-asdif2309fj'
```


Expand Down
5 changes: 5 additions & 0 deletions example.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ async def connect(args: argparse.Namespace, session: ClientSession) -> None:
tracks.append(item)
LOGGER.info("Tracks: %s", tracks)

track_details = []
async for item in soundcloud.get_track_details_liked(me["id"]):
track_details.append(item)
LOGGER.info("Track details: %s", track_details)

stream_url = await soundcloud.get_stream_url(tracks[0])
LOGGER.info("Stream url for track %s: %r", tracks[0], stream_url)

Expand Down
25 changes: 13 additions & 12 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "soundcloudpy"
version = "1.0.0"
version = "1.0.1"
license = { text = "Apache-2.0" }
description = "Client for async connection to the Soundcloud api."
readme = "README.md"
Expand All @@ -13,8 +13,9 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = ["aiohttp>=3.8.4"]
dependencies = ["aiohttp>=3.11.11"]

[project.optional-dependencies]
# speedups = [
Expand All @@ -24,18 +25,18 @@ dependencies = ["aiohttp>=3.8.4"]
# "orjson>=3.8.9",
# ]
test = [
"black==24.2.0",
"codespell==2.2.6",
"black==24.10.0",
"codespell==2.3.0",
"isort==5.13.2",
"mypy==1.8.0",
"pre-commit==3.6.1",
"pre-commit-hooks==4.5.0",
"pylint==3.0.3",
"pytest==8.0.0",
"mypy==1.14.1",
"pre-commit==4.0.1",
"pre-commit-hooks==5.0.0",
"pylint==3.3.3",
"pytest==8.3.4",
"pytest-aiohttp==1.0.5",
"pytest-cov==4.1.0",
"ruff==0.2.1",
"safety==3.0.1",
"pytest-cov==6.0.0",
"ruff==0.8.5",
"safety==3.2.14",
]

[tool.codespell]
Expand Down
37 changes: 32 additions & 5 deletions soundcloudpy/soundcloudpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ async def get_track_details(self, track_id: str) -> dict[str, Any]:
headers=self.headers,
)

async def get_tracks_liked(self, limit: int = 0) -> AsyncGenerator[list[dict[str, Any]], None]:
async def get_tracks_liked(self, limit: int = 0) -> AsyncGenerator[dict[str, Any], None]:
"""Obtain the authenticated user's liked tracks.
:param limit: number of tracks to get. if 0, will fetch all tracks.
Expand All @@ -150,6 +150,27 @@ async def get_tracks_liked(self, limit: int = 0) -> AsyncGenerator[list[dict[str

yield track

async def get_track_details_liked(
self, user_id: str, limit: int = 0
) -> AsyncGenerator[list[dict[str, Any]], None]:
"""Obtain the authenticated user's liked tracks with details.
:param limit: number of tracks to get. if 0, will fetch all tracks.
:returns: list of track ids liked by the current user
"""
query_limit = limit
if query_limit == 0:
query_limit = 100

num_items = 0
async for track in self._paginated_query(
f"/users/{user_id}/track_likes", params={"limit": str(query_limit)}
):
num_items += 1
if num_items >= limit > 0:
return
yield track["track"]

async def get_track_by_genre_recent(self, genre: str, limit: int = 10) -> dict[str, Any]:
"""Get track by genre recent.
Expand Down Expand Up @@ -202,11 +223,13 @@ async def get_popular_tracks_user(self, user_id: str, limit: int = 12) -> dict[s

# ---------------- PLAYLISTS ----------------

async def get_account_playlists(self) -> AsyncGenerator[list[dict[str, Any]], None]:
async def get_account_playlists(self) -> AsyncGenerator[dict[str, Any], None]:
"""Get account playlists, albums and stations."""
# NOTE: This returns all track lists in reverse chronological order (most recent first).
async for playlist in self._paginated_query("/me/library/all"):
yield playlist
# Skip some kind of system playlists, they have a different structure.
if "playlist" in playlist:
yield playlist

async def get_playlist_details(self, playlist_id: str) -> dict[str, Any]:
""":param playlist_id: playlist id"""
Expand Down Expand Up @@ -337,7 +360,7 @@ async def _paginated_query(
self,
path: str,
params: dict[str, str] | None = None,
) -> AsyncGenerator[list[dict[str, Any]], None]:
) -> AsyncGenerator[dict[str, Any], None]:
"""Paginate response queries.
Soundcloud paginates its queries using the same pattern. As such, we leverage the
Expand Down Expand Up @@ -365,7 +388,11 @@ async def _paginated_query(
yield item

# Handle case when results requested exceeds number of actual results.
if int(params.get("limit", 0)) and len(response["collection"]) < int(params["limit"]):
if (
int(params.get("limit", 0))
and len(response["collection"]) < int(params["limit"])
and "next_href" not in response
):
return

try:
Expand Down

0 comments on commit 813bdd6

Please sign in to comment.