Skip to content

Instantly share code, notes, and snippets.

@Fornoth
Last active September 27, 2023 17:52
Show Gist options
  • Save Fornoth/562a2db691051c381a8f to your computer and use it in GitHub Desktop.
Save Fornoth/562a2db691051c381a8f to your computer and use it in GitHub Desktop.
Makes a device show up in spotify connect devices list, but nothing else yet
#!/bin/bash -ex
#Based off of https://github.com/wouterdevinck/clonos-poc-spotify/blob/master/src/go.sh
#Tested on an Rpi 1 (in a soft-float debian chroot)
libDir='lib'
libPath=$libDir'/libspotify_embedded_shared.so'
#Make lib directory
if [ ! -d $libDir ]; then
mkdir $libDir
fi
#Download library
if [ ! -f $libPath ]; then
url='https://github.com/sashahilton00/spotify-connect-resources/blob/master/Rocki%20Firmware/dlna_upnp/spotify/lib/libspotify_embedded_shared.so?raw=true'
wget -O $libPath $url
fi
#Compile
gcc -L$PWD/$libDir -o run main.c -lspotify_embedded_shared -lm
#Run
export LD_LIBRARY_PATH=$PWD/$libDir:$LD_LIBRARY_PATH
./run
#First run the command avahi-publish-service TestConnect _spotify-connect._tcp 4000 VERSION=1.0 CPath=/
import os
#To install flask, run pip install flask
from flask import Flask, request, abort, jsonify
app = Flask(__name__)
if os.environ.get('DEBUG'):
app.debug = True
@app.route('/', methods=['GET', 'POST'])
def index():
action = request.args.get('action') or request.form.get('action')
if not action:
return jsonify({
'status': 301,
'spotifyError': 0,
'statusString': 'ERROR-MISSING-ACTION'})
if action == 'getInfo':
return getInfo()
elif action == 'addUser':
return addUser()
else:
return jsonify({
'status': 301,
'spotifyError': 0,
'statusString': 'ERROR-INVALID-ACTION'})
def getInfo():
return jsonify({
'status': 101,
'spotifyError': 0,
'activeUser': '',
'brandDisplayName': 'Test',
'accountReq': 'PREMIUM',
#Doesn't have any specific format (I think)
'deviceID': '0000000000000000',
#Not sure how these are generated (this string is just some random letters I typed)
#Possibly generated from SpZeroConfGetVars()
#Used to encrypt the blob used for login
'publicKey': 'sdfkdlfgkldfoglsdjifdkljgsdkfljgklsfglkfjsngkjsfhjksfnljknnjkfldhg',
'version': '2.0.1',
#Valid types are UNKNOWN, COMPUTER, TABLET, SMARTPHONE, SPEAKER, TV, AVR, STB and AUDIODONGLE
'deviceType': 'AUDIODONGLE',
'modelDisplayName': 'TEST000',
#Status codes are ERROR-OK (not actually an error), ERROR-MISSING-ACTION, ERROR-INVALID-ACTION, ERROR-SPOTIFY-ERROR, ERROR-INVALID-ARGUMENTS, ERROR-UNKNOWN, and ERROR_LOG_FILE
'statusString': 'ERROR-OK',
#Name that shows up in the Spotify client
'remoteName': 'TestConnect'
})
def addUser():
args = request.form
userName = args.get('userName')
blob = args.get('blob')
clientKey = args.get('clientKey')
#Username, blob, and clientKey would be passed to SpConnectionLoginZeroConf, and then SpConnectionLoginZeroConf decrypts the blob, and calls SpConnectionLoginBlob
#SpConnectionLoginZeroConf(userName, blob, clientKey)
#SpConnectionLoginBlob(userName, decrypted_blob)
# Would return this on success
# return jsonify({
# 'status': 101,
# 'spotifyError': 0,
# 'statusString': 'ERROR-OK'
# })
abort(400)
if __name__ == "__main__":
#Can be run on any port as long as it matches the one used in avahi-publish-service
app.run("", 4000)
#!/bin/bash -ex
#Based off of https://github.com/wouterdevinck/clonos-poc-spotify/blob/master/src/go.sh
#Tested on an Rpi 1 (in a soft-float debian chroot)
libDir='lib'
libPath=$libDir'/libspotify_embedded_shared.so'
#Make lib directory
if [ ! -d $libDir ]; then
mkdir $libDir
fi
#Download library
if [ ! -f $libPath ]; then
url='https://github.com/sashahilton00/spotify-connect-resources/blob/master/Rocki%20Firmware/dlna_upnp/spotify/lib/libspotify_embedded_shared.so?raw=true'
wget -O $libPath $url
fi
#Compile
gcc -L$PWD/$libDir -o run main.c -lspotify_embedded_shared -lm
#Run
export LD_LIBRARY_PATH=$PWD/$libDir:$LD_LIBRARY_PATH
./run

#Python Script Setup

To get the python script running, run either pip install flask or pip install -r requirements.txt if you used git clone to clone the gist

#libspotify_embedded_shared.so notes

##Using the library (still in progress) There's a compile.sh that compiles a program that calls SpInit(), but doesn't get any farther because it needs more than just the API version number (which is 4)

##Spotify appkey

An appkey (from https://devaccount.spotify.com/my-account/keys/) is passed somewhere into the library, but I haven't figured out where yet

##Library trace

This is output from running latrace on a program that uses libspotify_connect_embedded.so

###Startup

 5743     SpInit [libspotify_embedded_shared.so]  
 5743       SpSetDisplayName [libspotify_embedded_shared.so]  
 5743     SpRegisterConnectionCallbacks [libspotify_embedded_shared.so]  
 5743     SpRegisterDebugCallbacks [libspotify_embedded_shared.so]  
 5743     SpRegisterPlaybackCallbacks [libspotify_embedded_shared.so]  
 5743     SpPlaybackUpdateVolume [libspotify_embedded_shared.so]  

###Run every time devices list is opened

 5747     SpZeroConfGetVars [libspotify_embedded_shared.so]  

###After a device is selected

 5748     SpConnectionLoginZeroConf [libspotify_embedded_shared.so]  
 5748       SpConnectionLoginBlob [libspotify_embedded_shared.so]  
 5743       SpPlaybackUpdateVolume [libspotify_embedded_shared.so]  

#Updates

##3/4/15

Added info about SpConnectionLoginZeroConf, and that its directly used for login instead of SpConnectionLoginBlob
Added info about how the public key is possibly generated from SpZeroConfGetVars()

##3/6/15

Added info about needing an appkey

##3/7/15

Added SPEAKER, TV, AVR, and STB device types
Added notes about blob being encrypted

##3/8/15 Added initital program that links against the library, and some notes about it

##3/9/15 Automatically download library for compile.sh

##3/10/15 Added SpInit() struct

Flask==0.10.1
Jinja2==2.7.3
MarkupSafe==0.23
Werkzeug==0.10.1
argparse==1.2.1
distribute==0.6.24
itsdangerous==0.24
wsgiref==0.1.2
typedef struct spOptions {
int apiVersion;
int int1;
void *void1;
const void appkey;
size_t appkeySize;
const char *deviceID;
char *displayName;
const char *manufacturer;
const char *model;
const char deviceType;
int int2;
} spOptions;
@wackazong
Copy link

Can this be used to to discover a Spotify Connect device on the local network and log it in to Spotify so that it is visible in the Web API? This is what I am looking for, and others, too: https://stackoverflow.com/questions/56001560/programatically-onboard-a-spotify-connect-device-to-my-account

@Leshauts
Copy link

I'm trying to do the same thing, did it worked?

@wackazong
Copy link

Yes, works for me with spotifyd.

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