Skip to content

Commit 5182578

Browse files
authored
Merge pull request #317 from akbad/add-contrib-docs
Add rudimentary `CONTRIBUTING.md`
2 parents 76983a4 + bc3b0d1 commit 5182578

1 file changed

Lines changed: 138 additions & 0 deletions

File tree

CONTRIBUTING.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Contributing
2+
3+
## What this library is
4+
5+
- A headless Spotify client, allowing you to **authenticate and retrieve a decrypted audio stream for any track**.
6+
- *Not* a standalone audio player: the **provided stream must be piped to another application** (like `ffplay`) or handled by a server to be played.
7+
8+
## Environment setup
9+
10+
### Prerequisites
11+
- Python 3.10+
12+
13+
### Install runtime packages
14+
15+
```sh
16+
pip install -r requirements.txt
17+
```
18+
19+
### Install protoc
20+
21+
> This step is **only needed if you're changing any `.proto` serialization schema files**,
22+
> which will subsequently require using the protoc compiler to generate updated versions of
23+
> the `*_pb2.py` Python stubs that implement serialization/deserialization for those schemas.
24+
25+
- Go to the [protobuf release matching the version pinned in `requirements.txt`](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.1).
26+
- Download and install the `protoc-*.zip` file meant for your platform.
27+
28+
After modifying the `.proto` files you need to, **make sure to follow [these steps](#protocol-buffer-generation) to regenerate the Python stubs**.
29+
30+
## Protocol buffer generation
31+
32+
> These steps are only necessary after changing `.proto` files.
33+
34+
- From the repository root, conveniently recompile all `.proto` schema files with this command:
35+
36+
```bash
37+
find proto -name "*.proto" | xargs protoc -I=proto --python_out=librespot/proto
38+
```
39+
40+
- Alternatively, to recompile a single file (e.g. `proto/metadata.proto`), run:
41+
42+
```bash
43+
protoc -I=proto --python_out=librespot/proto proto/metadata.proto
44+
```
45+
46+
- Commit both the source `.proto` and the regenerated Python output **together** so they can
47+
be compared easily.
48+
49+
## Architecture
50+
51+
The main components are:
52+
53+
- **`Session` class** *(entrypoint)*
54+
55+
- `Session.Builder` is used to configure and create a session, via one of:
56+
57+
- username/password
58+
- stored credentials
59+
- OAuth
60+
61+
- An active session is **required** for all other operations.
62+
63+
- **`ApiClient` class**
64+
65+
- A high-level client for making standard HTTPS requests to Spotify's Web API endpoints (e.g., `https://spclient.wg.spotify.com`).
66+
- Accessed via `session.api()`, it provides convenient methods like `get_metadata_4_track()` and handles client tokens automatically.
67+
68+
- **`MercuryClient` class**
69+
70+
- The low-level client for Spotify's proprietary `mercury` protocol, which uses `hm://` URIs.
71+
- Accessed via `session.mercury()`, it handles sending and receiving messages over the main session connection for metadata lookups and subscriptions that are not available via the standard Web API.
72+
73+
- **`DealerClient` class**
74+
75+
- Manages the persistent WebSocket (`wss://`) connection to Spotify's `dealer` service.
76+
- Accessed via `session.dealer()`, it listens for and dispatches real-time, asynchronous JSON-based events, such as remote player state changes or notifications from other connected devices.
77+
78+
- **`Session.Receiver` thread**
79+
80+
- Spawned after authentication to read every encrypted packet coming from the access point.
81+
- Routes decoded commands to subsystems (`MercuryClient`, `AudioKeyManager`, `ChannelManager`, etc.) and responds to keep-alive pings to hold the session open.
82+
83+
- **Metadata types**
84+
85+
- The `librespot.metadata` module provides typed identifiers (`TrackId`, `AlbumId`, `PlaylistId`, `EpisodeId`, etc.) used to reference Spotify content throughout the API.
86+
- They are constructed from Spotify identifiers, typically using one of the following methods:
87+
88+
- `from_uri()`: For all ID types.
89+
- `from_base62()`: For most ID types (e.g., tracks, albums, artists).
90+
91+
- **`PlayableContentFeeder` class**
92+
93+
- Retrieves audio streams; is accessed via `session.content_feeder()`.
94+
- `load(playable_id, audio_quality_picker, preload, halt_listener)`:
95+
96+
- Accepts:
97+
98+
- a `TrackId` or `EpisodeId` (any `PlayableId`)
99+
- an `AudioQualityPicker`
100+
- a `preload` flag
101+
- an optional `HaltListener` callback (pass `None` if unneeded).
102+
103+
- Returns a `LoadedStream` that contains the decrypted stream together with:
104+
105+
- track/episode metadata
106+
- normalization data
107+
- transfer metrics
108+
109+
- **`audio` module**
110+
111+
- Contains tools for format selection, quality management, streaming, and decryption.
112+
- `VorbisOnlyAudioQuality` and `LosslessOnlyAudioQuality` choose the best matching `Metadata.AudioFile` for a preferred container/quality combination.
113+
- `CdnManager` acquires and refreshes signed CDN URLs, feeding a `Streamer` that decrypts chunks on the fly while staying seekable.
114+
115+
- **`AudioKeyManager` and `ChannelManager`**
116+
117+
- Handle the low-level transport for protected audio: `AudioKeyManager` requests AES keys, and `ChannelManager` can stream encrypted chunks directly from the access point when CDN delivery is unavailable.
118+
- Both are driven transparently by `PlayableContentFeeder`/`CdnManager`, so callers only interact with the decrypted `LoadedStream`.
119+
120+
- **`EventService` class**
121+
122+
- Asynchronous publisher that emits telemetry (e.g., fetch metrics, playback events) to `hm://event-service/v1/events` via Mercury.
123+
- Accessible through `session.event_service()` for consumers that need to forward custom events.
124+
125+
- **`TokenProvider` class**
126+
127+
- Caches Login5 access tokens per scope, refreshing them proactively as they near expiry.
128+
- Used by `ApiClient` to supply the correct `Authorization` headers for Spotify Web API calls.
129+
130+
- **`SearchManager` class**
131+
132+
- High-level wrapper around `hm://searchview/km/v4/search/...` requests sent over Mercury.
133+
- Fills in username, locale, and country defaults from the current session before dispatching the call.
134+
135+
- **OAuth tokens for Spotify Web API**
136+
137+
- Can be obtained via `session.tokens().get(scope)`
138+
- Enable authenticated API calls for operations like search, playlist management, and user data access

0 commit comments

Comments
 (0)