-
Notifications
You must be signed in to change notification settings - Fork 638
Events
With librespot --onevent=/path/to/my/event/script/program
users can subscribe to non-blocking events. By also passing emit-sink-events
users can also subscribe to blocking sink events with the same script/program. The purpose of blocking sink events is to block the player thread to allow for something to be done before the sink is opened or after it is closed.
The type of script/program you use to handle events is completely up to you, librespot
simply runs the script/program every time an event is fired and passes events via environment variables.
PLAYER_EVENT
will contain the name of the Event. Additional environment variables will follow depending on the Event.
The mapping is as follows:
Non-blocking events are non-blocking in every sense. They do not block librespot
threads in any way and the event script/program is run in it's own separate thread for each and every event. librespot
's event handler does not wait for event scripts/programs to exit before it fires the next event. This can lead to data race situations if the events take a variable amount of time for the script/program to process. It is up to the user to keep track of event sequencing. This has been fixed in dev.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | changed |
Name of the Event |
OLD_TRACK_ID | Spotify Track ID | ID of the previous Track |
TRACK_ID | Spotify Track ID | ID of the new Track |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | started |
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | stopped |
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | playing |
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
DURATION_MS | Milliseconds | Duration in ms |
POSITION_MS | Milliseconds | Position in ms |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | paused |
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
DURATION_MS | Milliseconds | Duration in ms |
POSITION_MS | Milliseconds | Position in ms |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | preloading |
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | volume_set |
Name of the Event |
VOLUME | volume | Volume 0 - 65535 |
Blocking events are blocking in every sense. They block librespot
's player thread and also therefore block themselves. librespot
's player thread will not unblock until the event script/program exits. Blocking events will not be fired by default for that reason. Use blocking events with care.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | sink |
Name of the Event |
SINK_STATUS | running |
The sink is about to be opened |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | sink |
Name of the Event |
SINK_STATUS | temporarily_closed |
The sink has closed, but more than likely will be reopened very shortly |
Key | Value | Description |
---|---|---|
PLAYER_EVENT | sink |
Name of the Event |
SINK_STATUS | closed |
The sink has closed |
Here is an example Python skeleton to further illustrate:
#!/usr/bin/python3
import os
# Non-blocking Events
if os.environ['PLAYER_EVENT'] == 'changed':
old_track_id = os.environ['OLD_TRACK_ID']
new_track_id = os.environ['TRACK_ID']
# do stuff
elif os.environ['PLAYER_EVENT'] == 'started':
track_id = os.environ['TRACK_ID']
# do suff
elif os.environ['PLAYER_EVENT'] == 'stopped':
track_id = os.environ['TRACK_ID']
# do stuff
elif os.environ['PLAYER_EVENT'] == 'playing':
track_id = os.environ['TRACK_ID']
track_duration_ms = os.environ['DURATION_MS']
track_position_ms = os.environ['POSITION_MS']
# do stuff
elif os.environ['PLAYER_EVENT'] == 'paused':
track_id = os.environ['TRACK_ID']
track_duration_ms = os.environ['DURATION_MS']
track_position_ms = os.environ['POSITION_MS']
# do stuff
elif os.environ['PLAYER_EVENT'] == 'preloading':
track_id = os.environ['TRACK_ID']
# do stuff
elif os.environ['PLAYER_EVENT'] == 'volume_set':
volume = os.environ['VOLUME']
# do stuff
# Blocking Events
elif os.environ['PLAYER_EVENT'] == 'sink':
status = os.environ['SINK_STATUS']
if status == 'running':
# do stuff
elif status == 'temporarily_closed':
# do stuff
elif status == 'closed':
# do stuff
Non-blocking events do not block librespot
threads but are buffered and blocking to themselves so that subsequent events are not fired until the event script/program exits after processing the previous event to help guarantee that event scripts/programs do not process events out of order.
Fired when a user connects to / disconnects from librespot
.
Session Connected events will be followed immediately by Client Changed, Volume Changed, Auto Play Changed, Filter Explicit Content, Shuffle Changed, and Repeat Changed events so that event consumers will have the initial state of the session.
These Events both share common fields, just PLAYER_EVENT
is different.
Key | Value | Description |
---|---|---|
PLAYER_EVENT |
session_connected / session_disconnected
|
Name of the Event |
USER_NAME | User Name | Session User Name (really an ID not a display name) |
CONNECTION_ID | Connection ID | Session Connection ID |
Fired when the Client changes or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | session_client_changed |
Name of the Event |
CLIENT_ID | Client ID | ID of the Client |
CLIENT_NAME | Client Name | Name of the Client |
CLIENT_BRAND_NAME | Client Brand Name | Brand Name of the Client |
CLIENT_MODEL_NAME | Client Model Name | Model Name of the Client |
Fired when the Volume changes or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | volume_changed |
Name of the Event |
VOLUME | volume | Volume 0 - 65535 |
Fired when the Shuffle toggle is flipped or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | shuffle_changed |
Name of the Event |
SHUFFLE | True/False | State of the Shuffle toggle |
Fired when the Repeat toggle is flipped or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | repeat_changed |
Name of the Event |
REPEAT | True/False | State of the Repeat toggle |
Fired when the Auto Play toggle is flipped or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | auto_play_changed |
Name of the Event |
AUTO_PLAY | True/False | State of the Auto Play toggle |
Fired when the Filter Explicit Content toggle is flipped or immediately after a Session Connected event.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | filter_explicit_content_changed |
Name of the Event |
FILTER | True/False | State of the Filter Explicit Content toggle |
Fired when the Track changes.
Track Changed has Common Fields shared by both Tracks and Episodes and Fields unique to Tracks and Episodes.
Key | Value | Description |
---|---|---|
PLAYER_EVENT | track_changed |
Name of the Event |
ITEM_TYPE |
Track / Episode
|
Track or Episode |
TRACK_ID | Spotify Track ID | ID of the Track |
URI | URI | URI of the Track |
NAME | Name | Name of the Track |
DURATION_MS | Milliseconds | Duration in ms |
IS_EXPLICIT | True/False | If the Track is Explicit |
LANGUAGE | Languages |
\n separated list of Languages |
COVERS | Cover urls |
\n separated list of Cover urls from largest to smallest in size |
Key | Value | Description |
---|---|---|
NUMBER | Track Number | Number of the Track as it appears on the album |
DISC_NUMBER | Disc Number | Disc Number of the Track as it appears on the album |
POPULARITY | Popularity | Popularity of the Track 0 - 100 |
ALBUM | Album | Album the Track appears on |
ARTISTS | Artists |
\n separated list of the artists that appear on the Track |
ALBUM_ARTISTS | Album Artists |
\n separated list of the artists of the album |
Key | Value | Description |
---|---|---|
SHOW_NAME | Show Name | Name of the Show |
PUBLISH_TIME | Unix Timestamp | Unix Timestamp of the Publish Time |
DESCRIPTION | Description | Description of the Show/Episode |
Playing / Paused are fired when librespot
is in the respectively state.
Seeked / Position Correction are fired when the position changes due to a seek or an internal librespot
position correction. Track position can be assumed to be advancing at a normal rate otherwise.
These Events all share common fields, just PLAYER_EVENT
is different.
Key | Value | Description |
---|---|---|
PLAYER_EVENT |
playing / paused / seeked / position_correction
|
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
POSITION_MS | Milliseconds | Position in ms |
Unavailable / Preload Next / Preloading / Loading represent internal librespot
states and are useful mainly for debugging.
Stopped is fired when librespot
stops.
End of Track is fired at the end of a Track.
These Events all share common fields, just PLAYER_EVENT
is different.
Key | Value | Description |
---|---|---|
PLAYER_EVENT |
unavailable / end_of_track / preload_next / preloading / loading / stopped
|
Name of the Event |
TRACK_ID | Spotify Track ID | ID of the Track |
Blocking Events and behavior have not changed and are identical to that of Released - master
.
An example non-blocking Event Python script can be found Here.
Refer to the above Released - master
Example for Blocking Events.