Skip to content

Instantly share code, notes, and snippets.

@jgamblin
Created April 19, 2017 01:10
Show Gist options
  • Save jgamblin/9701ed50398d138c65ead316b5d11b26 to your computer and use it in GitHub Desktop.
Save jgamblin/9701ed50398d138c65ead316b5d11b26 to your computer and use it in GitHub Desktop.
A Script To Set Current Spotify Song As Slack Status
#!/bin/bash
APIKEY="From Here https://api.slack.com/custom-integrations/legacy-tokens"
SONG=$(osascript -e 'tell application "Spotify" to name of current track as string')
URLSONG=$(echo "$SONG" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"')
while true
do
curl -s -d "payload=$json" "https://slack.com/api/users.profile.set?token="$APIKEY"&profile=%7B%22status_text%22%3A%22"$URLSONG"%22%2C%22status_emoji%22%3A%22%3Amusical_note%3A%22%7D" > /dev/null
sleep 60
done
@nickolai-voyage
Copy link

nickolai-voyage commented Mar 26, 2020

For linux users, I found a notify stackoverflow page that provides a way of getting the track from CLI: https://askubuntu.com/questions/852366/how-to-get-the-name-of-the-music-currently-playing-in-spotify/852387#852387

In short, replace

SONG=$(osascript ...)

with

SONG=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata | sed -n '/title/{n;p}' | cut -d '"' -f 2)

And you should be good to go.

I have my own crappy mod to that string that will print out "Song by Author" instead of just the song title:

SONG=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata | egrep -A 2 "title|artist" | grep -v xesam | grep string | awk -F\" '{if (NR == 1) {author=$2} else {print $2" by "author}}')

I'm not sure how to use this to get the state though, so my script just doesn't include that part of the functionality.

Edit: Figured out how to get the state. It's simply asking for PlaybackStatus instead of Metadata in the dbus command. Here's my script in full, including status updates and clear-on-exit, tested on Ubuntu 18.04

#!/bin/bash
APIKEY="Your API key here"

trap onexit INT

function reset() {
    echo 'Resetting status'
    curl -s -d "payload=$json" "https://slack.com/api/users.profile.set?token="$APIKEY"&profile=%7B%22status_text%22%3A%22%22%2C%22status_emoji%22%3A%22%22%7D" > /dev/null
}

function onexit() {
    echo 'Exiting'
    reset
    exit
}


while true
    SONG=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Metadata | egrep -A 2 "title|artist" | grep -v xesam | grep string | awk -F\" '{if (NR == 1) {author=$2} else {print $2" by "author}}')
    # SONG=$(osascript -e 'tell application "Spotify" to name of current track as string')
    URLSONG=$(echo "$SONG" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"')
    PLAYBACK_STATUS=$(dbus-send --print-reply --dest=org.mpris.MediaPlayer2.spotify /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:PlaybackStatus | grep variant | awk -F\" '{print $2}')

do
    if [ "$PLAYBACK_STATUS" == "Playing" ]; then
        echo $URLSONG
        curl -s -d "payload=$json" "https://slack.com/api/users.profile.set?token="$APIKEY"&profile=%7B%22status_text%22%3A%22"$URLSONG"%22%2C%22status_emoji%22%3A%22%3Amusical_note%3A%22%7D"
    else
        echo $PLAYBACK_STATUS
        reset
    fi
    echo "Sleeping"
    sleep 60 
done

@ksession
Copy link

Has anyone come across any issues with this script lately? It displays "-" for the song playing and no other details.

@rwakefield
Copy link

Yes

@josephmcasey
Copy link

josephmcasey commented May 14, 2020

For anyone looking to use this behind an enterprise slack. I created a script based off @agologan that utilizes a custom osascript from @samknight (https://github.com/samknight/slack_applescript)

#!/bin/bash
trap onexit INT

function reset() {
    echo 'Resetting status'
    osascript -e 'tell script "Slack" to clear status'
}

function onexit() {
    echo 'Exiting'
    reset
    exit
}

while true; do
    state=$(osascript -e 'tell application "Spotify" to player state')

    date
    echo "Spotify: "$state

    if [[ "$state" != "playing" ]]; then
        reset
    else
        SONG=$(osascript -e 'tell application "Spotify" to artist of current track & " - " & name of current track')
        echo $SONG

        osascript -e 'tell script "Slack" to set status "'"$SONG"'" with icon ":spotify:"'
    fi

    sleep 60
done

@fastfrwrd , you might like this.

@RasPat1
Copy link

RasPat1 commented Dec 19, 2020

Here's a way to have a channel that shares the now playing for any arbitrary number of users. This is really nice for medium-sized organizations, but requires you to enable a webhook. https://github.com/RasPat1/spotify-slack-integration-webhook

  # These can be passed in as args:
  #
  # #########################################
  # osascript spotify.scpt  WEBHOOK_URL USERNAME CHANNEL_NAME
  # #########################################
  #

  property webhookURL : "<WEBHOOK URL>"
  property userName : "<USERNAME>"
  property channelName : "#musical-chairs"

  # globals
  property emojiName : "musical_note"
  property possibleAppList : {"Spotify", "iTunes", "Rdio"}
  property installedAppList : {"Spotify"}
  property chosenApp : "Spotify"


  on replace_chars(this_text, search_string, replacement_string)
    set AppleScript's text item delimiters to the search_string
    set the item_list to every text item of this_text
    set AppleScript's text item delimiters to the replacement_string
    set this_text to the item_list as string
    set AppleScript's text item delimiters to ""
    return this_text
  end replace_chars


  # content
  tell application "Spotify"
    set current_track to null
    set current_artist to null
    set current_album to null

    repeat until application "Spotify" is not running
      if player state is playing then
        set track_name to name of current track
        set track_artist to artist of current track
        set track_album to album of current track

        if track_name ≠ current_track then
          set current_track to name of current track
          set current_artist to artist of current track
          set current_album to album of current track

          set message to current_track & " -  " & current_artist & " - " & userName
          set encodedMessage to my replace_chars(message, "\"", "\\\"")

          #       do shell script "curl -X POST --data-urlencode payload={\"channel\": \"#music\", \"username\": \"nowplaying\", \"attachments\": [ { \"fallback\": \"$USERNAME is now playing: " & encodedMessage & "\", \"pretext\": \"$USERNAME is now playing:\", \"text\": \"" & encodedMessage & "\", \"color\": \"#7CD197\"} ], \"icon_emoji\": \":musical_note:\"} https://hooks.slack.com/services/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"
          do shell script "curl -X POST --data-urlencode 'payload={\"channel\": \"" & channelName & "\", \"text\": \"" & encodedMessage & "\", \"icon_emoji\": \":" & emojiName & ":\"}' " & webhookURL
        end if

        delay 5
      end if
    end repeat

  end tell
end script
on run argv
  if (count of argv) > 0 then
    tell myScript
      set its webhookURL to item 1 of argv
    end tell
  end if
  if (count of argv) > 1 then
    tell myScript
      set its userName to item 2 of argv
    end tell
  end if
  if (count of argv) > 2 then
    tell myScript
      set its channelName to item 3 of argv
    end tell
  end if

  run myScript
end run```

@crevulus
Copy link

Does anyone have an update for this now that legacy tokens are deprecated in slack? I was planning to follow @tiagocasanovapt 's readme/guide, but it seems like that will no longer work.

@alex-jerechinsky
Copy link

@Mexidense
Copy link

@crevulus this might interest you https://github.com/giorgimode/SpotMyStatus/

Thanks! Looks soooo good!

@TheMY3
Copy link

TheMY3 commented Feb 9, 2022

@crevulus this might interest you https://github.com/giorgimode/SpotMyStatus/

Works good, ty :)

@TomasHubelbauer
Copy link

TomasHubelbauer commented Jan 3, 2023

My contribution using the new token format and hopefully very clear and readable:

# Get this token by:
# - Creating a Slack app https://api.slack.com/apps
# - Select Permissions > Scopes > User Token Scopes and add `users.profile:write`
# - Scroll up and select Install to Workspace under OAuth Tokens for Your Workspace
# - Copy User OAuth Token under OAuth Tokens for Your Workspace
TOKEN=$(cat slack.pat)

while true
do
  echo "Stamp:"
  date -Iseconds

  RUNNING=$(pgrep -lf Spotify)
  # Bail if Spotify is not running to prevent `osascript` from launching it
  if [ -z "$RUNNING" ];
  then
    echo "Spotify is off, waiting a minute…"
    sleep 60
    continue
  fi

  # See `/Applications/Spotify.app/Contents/Resources/Spotify.sdef`
  ARTIST=$(osascript -e 'tell application "Spotify" to artist of current track')
  SONG=$(osascript -e 'tell application "Spotify" to name of current track')

  # Bail if Spotify is not playing anything (but is running)
  if [ -z "$ARTIST" ] || [ -z "$SONG" ];
  then
    echo "Spotify is not playing anything, waiting a minute…"
    sleep 60
    continue
  fi

  STAMP=$(date -v"+5M" +%s)
  JSON=$(echo '{}' | jq --arg SONG "$SONG" --arg ARTIST "$ARTIST" --arg STAMP $STAMP '.profile.status_text=$ARTIST+" - "+$SONG | .profile.status_emoji=":headphones:" | .profile.status_expiration=($STAMP|tonumber)')
  echo "Request:"
  echo "$JSON" | jq '.'

  # See https://api.slack.com/docs/presence-and-status#custom_status
  echo "Response:"
  curl -X POST --data "$JSON" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json; charset=utf-8" --no-progress-meter https://slack.com/api/users.profile.set | jq 'del(.profile)'

  # Wait for a minute in between the status updates
  sleep 60
  echo ""
done

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