Skip to content
Jason Gray edited this page Sep 25, 2022 · 19 revisions

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.

Event Keys and Values

PLAYER_EVENT will contain the name of the Event. Additional environment variables will follow depending on the Event.

The mapping is as follows:

Released - master

Non-blocking Events

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.

Changed

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

Started

Key Value Description
PLAYER_EVENT started Name of the Event
TRACK_ID Spotify Track ID ID of the Track

Stopped

Key Value Description
PLAYER_EVENT stopped Name of the Event
TRACK_ID Spotify Track ID ID of the Track

Playing

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

Paused

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

Preloading

Key Value Description
PLAYER_EVENT preloading Name of the Event
TRACK_ID Spotify Track ID ID of the Track

Volume Set

Key Value Description
PLAYER_EVENT volume_set Name of the Event
VOLUME volume Volume 0 - 65535

Blocking Events

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.

Running

Key Value Description
PLAYER_EVENT sink Name of the Event
SINK_STATUS running The sink is about to be opened

Temporarily Closed (Transient State)

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

Closed

Key Value Description
PLAYER_EVENT sink Name of the Event
SINK_STATUS closed The sink has closed

Example

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

Unreleased - dev

Non-blocking Events

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 script/program do not process events out of order.

Track Changed

Track Changed has Common Fields shared by both Tracks and Episodes and Fields unique to Tracks and Episodes.

Common Fields

Key Value Description
PLAYER_EVENT track_changed Name of the Event
ITEM_TYPE Track / Episode Track or Episode
TRACK_ID Uri Uri of the Track
URI Spotify Track ID ID 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

Track Item Type Specific Fields

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

Episode Item Type Specific Fields

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

Session Connected / Session Disconnected

These Events all 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

Session Client Changed

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

Playing / Paused / Seeked / Position Correction

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 / End of Track / Preload Next / Preloading / Loading / Stopped

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

Volume Changed

Key Value Description
PLAYER_EVENT volume_changed Name of the Event
VOLUME volume Volume 0 - 65535

Shuffle Changed

Key Value Description
PLAYER_EVENT shuffle_changed Name of the Event
SHUFFLE True/False State of the Shuffle toggle

Repeat Changed

Key Value Description
PLAYER_EVENT repeat_changed Name of the Event
REPEAT True/False State of the Repeat toggle

Auto Play Changed

Key Value Description
PLAYER_EVENT auto_play_changed Name of the Event
AUTO_PLAY True/False State of the Auto Play toggle

Filter Explicit Content Changed

Key Value Description
PLAYER_EVENT filter_explicit_content_changed Name of the Event
FILTER True/False State of the Filter Explicit Content toggle

Blocking Events

Blocking Events and behavior have not changed and are identical to that of Released - master.

Example

An example non-blocking Event Python script can be found Here.

Refer to the above Released - master example for Blocking Events.

Clone this wiki locally