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
@mihaerzen
Copy link

This script sets the same song every 60 seconds...

This is fixed one:

#!/bin/bash
APIKEY="From Here https://api.slack.com/custom-integrations/legacy-tokens"

while true

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"')

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

@agologan
Copy link

Few other improvements like resetting status on pause or script exit.

#!/bin/bash

APIKEY="From Here https://api.slack.com/custom-integrations/legacy-tokens"
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 'Exitting'
    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')
        URLSONG=$(echo "$SONG" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"')
        echo $SONG

        curl -s -d "payload=$json" "https://slack.com/api/users.profile.set?token="$APIKEY"&profile=%7B%22status_text%22%3A%22"$URLSONG"%20on%20Spotify%22%2C%22status_emoji%22%3A%22%3Aheadphones%3A%22%7D"  > /dev/null
    fi

    sleep 60
done

@apanzerj
Copy link

apanzerj commented Jun 5, 2018

Just a note, if you don't normally use perl, you'll need to isntall uri::escape. Do so by doing this:

perl -MCPAN -e shell

You should get a prompt, then type:

install URI::Escape

@enok82
Copy link

enok82 commented Jun 13, 2018

Might be worth a mention that this is a Mac OS script.
Other .sh using OS' such as Ubuntu and others does not have the osascript (Mac OS Apple Script) facilities.

@xron89
Copy link

xron89 commented Jun 27, 2018

Would be great if someone could add a readme on how to run this! Thanks

@tiagocasanovapt
Copy link

@xron89, on Mac OS:


for the perl setup, like @apanzerj mentioned:

  • perl -MCPAN -e shell
  • yes - (for the "...configure automatically" question)
  • install URI::Escape
  • ...wait for it to finish...
  • exit

Thank you for the script, we'll be using it daily at the office! 👍

@frogamic
Copy link

frogamic commented Dec 2, 2018

You can have this run automatically on your mac using the native launchd system:

  1. Drop the following PLIST into ~/Library/LaunchAgents/com.user.slack-spotify.plist:
    The filename must match the string under Label, replace /PATH/TO/SCRIPT.sh with an actual path to the .sh script above.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>com.user.slack-spotify</string>
        <key>ProgramArguments</key>
        <array><string>/PATH/TO/SCRIPT.sh</string></array>
        <key>RunAtLoad</key>
        <true/>
        <key>StartInterval</key>
        <integer>60</integer>
    </dict>
</plist>
  1. Since this also runs on its own timer, remove the following 3 lines from the .sh script:
while true; do
    sleep 60
done
  1. Register this daemon with launchd by running
    launchctl load ~/Library/LaunchAgents/com.user.slack-spotify.plist

  2. start it by either logging out and back in or running
    launchctl start com.user.slack-spotify

@muffincode
Copy link

@agologan, based on what you did, here's my version, to reset the status to something explicitely written in the script :

#!/bin/bash

# Get it from here : https://api.slack.com/custom-integrations/legacy-tokens
APIKEY="XXXXXXXXXX"

trap onexit INT

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

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')
        URLSONG=$(echo "$SONG" | perl -MURI::Escape -ne 'chomp;print uri_escape($_),"\n"')
        echo $SONG

        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%3Aheadphones%3A%22%7D"  > /dev/null
    fi

    sleep 60
done

@Ralithune
Copy link

Thanks for the comments here, I'm using them! :)

@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

@fatihtoprak
Copy link

Any idea for tidal.app ? :)

@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