Skip to content

Instantly share code, notes, and snippets.

@tternes
Last active January 4, 2025 09:03
Show Gist options
  • Save tternes/fe1cfb354c89e1efe00c026fb1c81ce3 to your computer and use it in GitHub Desktop.
Save tternes/fe1cfb354c89e1efe00c026fb1c81ce3 to your computer and use it in GitHub Desktop.
Raspotify (librespot) JSON+MQTT Events
#!/bin/bash
# ----------------------------------------------------------------
# MQTT Configuration values
# Note: these values can either be defined in the environment, or
# in the raspotify conf file (/etc/raspotify/conf on Raspberry Pi OS)
#
# - LIBRESPOT_MQTT_HOST: the MQTT broker host/ip where events should be published
# - LIBRESPOT_MQTT_TOPIC: topic where events will be published
#
# ----------------------------------------------------------------
#
# The code below is based on the following example:
# https://github.com/librespot-org/librespot/blob/dev/contrib/event_handler_example.py
#
# The example was converted with ChatGPT
# ----------------------------------------------------------------
# Ensure jq is installed
if ! command -v jq &> /dev/null; then
echo "jq is required but not installed. Please install jq and try again."
exit 1
fi
# Get the PLAYER_EVENT environment variable
player_event="${PLAYER_EVENT}"
# Initialize the base JSON object with event_time and event
event_time=$(date +"%Y-%m-%d %H:%M:%S")
json=$(jq -n --arg event_time "$event_time" --arg event "$player_event" '{event_time: $event_time, event: $event}')
# Add fields based on PLAYER_EVENT
case "$player_event" in
session_connected|session_disconnected)
json=$(echo "$json" | jq --arg user_name "$USER_NAME" --arg connection_id "$CONNECTION_ID" \
'. + {user_name: $user_name, connection_id: $connection_id}')
;;
session_client_changed)
json=$(echo "$json" | jq --arg client_id "$CLIENT_ID" --arg client_name "$CLIENT_NAME" \
--arg client_brand_name "$CLIENT_BRAND_NAME" --arg client_model_name "$CLIENT_MODEL_NAME" \
'. + {client_id: $client_id, client_name: $client_name, client_brand_name: $client_brand_name, client_model_name: $client_model_name}')
;;
shuffle_changed)
json=$(echo "$json" | jq --arg shuffle "$SHUFFLE" '. + {shuffle: $shuffle}')
;;
repeat_changed)
json=$(echo "$json" | jq --arg repeat "$REPEAT" '. + {repeat: $repeat}')
;;
auto_play_changed)
json=$(echo "$json" | jq --arg auto_play "$AUTO_PLAY" '. + {auto_play: $auto_play}')
;;
filter_explicit_content_changed)
json=$(echo "$json" | jq --arg filter "$FILTER" '. + {filter: $filter}')
;;
volume_changed)
json=$(echo "$json" | jq --arg volume "$VOLUME" '. + {volume: $volume}')
;;
seeked|position_correction|playing|paused)
json=$(echo "$json" | jq --arg track_id "$TRACK_ID" --arg position_ms "$POSITION_MS" \
'. + {track_id: $track_id, position_ms: $position_ms}')
;;
unavailable|end_of_track|preload_next|preloading|loading|stopped)
json=$(echo "$json" | jq --arg track_id "$TRACK_ID" '. + {track_id: $track_id}')
;;
track_changed)
# Common metadata fields
common_metadata=$(jq -n --arg item_type "$ITEM_TYPE" --arg track_id "$TRACK_ID" --arg uri "$URI" \
--arg name "$NAME" --arg duration_ms "$DURATION_MS" --arg is_explicit "$IS_EXPLICIT" \
--argjson language "$(echo "$LANGUAGE" | jq -R -s -c 'split("\n") | map(select(length > 0))')" \
--argjson covers "$(echo "$COVERS" | jq -R -s -c 'split("\n") | map(select(length > 0))')" \
'{item_type: $item_type, track_id: $track_id, uri: $uri, name: $name, duration_ms: $duration_ms, is_explicit: $is_explicit, language: $language, covers: $covers}')
if [ "$ITEM_TYPE" == "Track" ]; then
# Track metadata fields
track_metadata=$(jq -n --arg number "$NUMBER" --arg disc_number "$DISC_NUMBER" \
--arg popularity "$POPULARITY" --arg album "$ALBUM" \
--argjson artists "$(echo "$ARTISTS" | jq -R -s -c 'split("\n") | map(select(length > 0))')" \
--argjson album_artists "$(echo "$ALBUM_ARTISTS" | jq -R -s -c 'split("\n") | map(select(length > 0))')" \
'{number: $number, disc_number: $disc_number, popularity: $popularity, album: $album, artists: $artists, album_artists: $album_artists}')
json=$(echo "$json" | jq --argjson common "$common_metadata" --argjson track "$track_metadata" \
'. + {common_metadata_fields: $common, track_metadata_fields: $track}')
elif [ "$ITEM_TYPE" == "Episode" ]; then
# Episode metadata fields
publish_time=$(date -u -d @"$PUBLISH_TIME" +"%Y-%m-%d")
episode_metadata=$(jq -n --arg show_name "$SHOW_NAME" --arg publish_time "$publish_time" \
--arg description "$DESCRIPTION" \
'{show_name: $show_name, publish_time: $publish_time, description: $description}')
json=$(echo "$json" | jq --argjson common "$common_metadata" --argjson episode "$episode_metadata" \
'. + {common_metadata_fields: $common, episode_metadata_fields: $episode}')
fi
;;
esac
# ----------------------------------------------------------------
# now we have json; publish to MQTT topic
#echo "$json" | logger
mosquitto_pub -h "$LIBRESPOT_MQTT_HOST" -t "$LIBRESPOT_MQTT_TOPIC" -m "$json"
@tternes
Copy link
Author

tternes commented Dec 25, 2024

The script above produces events like the following:

{
  "event_time": "2024-12-24 23:05:30",
  "event": "track_changed",
  "common_metadata_fields": {
    "item_type": "Track",
    "track_id": "06jYhkarVbcRsKcQaTZXJz",
    "uri": "spotify:track:06jYhkarVbcRsKcQaTZXJz",
    "name": "Winter Blessings",
    "duration_ms": "250713",
    "is_explicit": "false",
    "language": [
      "zxx",
    ],
    "covers": [
      "https://i.scdn.co/image/ab67616d0000b27306afd8641a8e72354c5b01eb",
      "https://i.scdn.co/image/ab67616d00001e0206afd8641a8e72354c5b01eb",
      "https://i.scdn.co/image/ab67616d0000485106afd8641a8e72354c5b01eb",
    ]
  },
  "track_metadata_fields": {
    "number": "1",
    "disc_number": "1",
    "popularity": "63",
    "album": "Winter Blessings",
    "artists": [
      "The Three Queens",
    ],
    "album_artists": [
      "The Three Queens",
    ]
  }
}
{
  "event_time": "2024-12-24 23:05:33",
  "event": "playing",
  "track_id": "06jYhkarVbcRsKcQaTZXJz",
  "position_ms": "0"
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment