I came across this semi-accidentally and I think that it is a really cool project. I can't wait to see what else you have going! In the meantime, the script on the front page doesn't work, so here is a modified version that goes through the new grooveshark api calls that a few people were discussing above. I switched the functions around a bit so it won't work with the gui or command line and it won't actually play, but you can at least see how the api works from a python shell and get an mp3 file spewed out in hex. Just open a shell and type in the commands listed in Usage.
'''
Main class for handling of grooveshark
one grooveshark instance represents one session (so usually one per application instance)
'''
import time
import sys
import uuid
import hashlib
import urllib
import os
import random
import subprocess
from mutagen.mp3 import MP3
try:
import json
except ImportError:
import simplejson as json#If this also errors allows the gui/user/whatever to handle the failed import
#Third Pary Libaries
import httplib2#Need version 5 or higher for python 2.6 compatability - No version info in httplib2 so I can not check this :(
#This is a default header that can be used if you just need a user agent change (this way not every function/method has to define this)
header = {}
header['user-agent'] = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)'
'''
Intialize Grooveshark
-- Get Session Data No Return
-- set ID3 tags No Return
-- Work methods
- search, return json search results
- songKeyfromID return songKey
- Download - return song
Usage:
from Grooveshark import Grooveshark
g = Grooveshark()
g.sessionData()
-Searching
g.search('some search string')
-Get Song Key and Stream server
g.songKeyfromID(songID)
-Download
g.download(songKey, streamServer)
-Popular Songs
g.Popular()
'''
class Grooveshark(object):
def __init__(self):
self.search_url = 'http://cowbell.grooveshark.com/more.php?getSearchResults'
self.count = 0
def save(self, content, path):
file_ = open(path, 'wb')
file_.write(content)
file_.close()
def sessionData(self):
self.session = self.getSessionID()
self.uuid = self.getUID()
self.token = self.getToken()
def getToken(self):
http = httplib2.Http()
url = 'https://cowbell.grooveshark.com/service.php'
self.secretKey = hashlib.md5(self.session).hexdigest()
tokenPOSTdata = ('''{"header":{"session":"%s","uuid":"%s","client":"gslite","clientRevision":"20100211.13"},'''
'''"parameters":{"secretKey":"%s"},"method":"getCommunicationToken"}''' % (self.session, self.uuid, self.secretKey))
request, reply = http.request(url, 'POST', headers = header, body = tokenPOSTdata)
return json.loads(reply)['result']
def getUID(self):
return uuid.uuid4()
def getSessionID(self):
http = httplib2.Http()
url = 'http://listen.grooveshark.com'
response, src = http.request(url, 'GET', headers = header)
src = src.lower().replace(' ', '')
start = src.find('session')
end = src[start:].find("',")
startSession = src[start:end+start].find("'") +1
return src[startSession+start:end+start]
def getRequestToken(self, method):
randomStr = ''.join([random.choice('0123456789abcdef') for x in xrange(6)])
return randomStr + hashlib.sha1(method + ":" + self.token + ":theColorIsRed:" + randomStr).hexdigest()
#work Methods
def search(self, search_string):
http = httplib2.Http()
data = ('''{"header":{"session":"%s","uuid":"%s","client":"gslite","clientRevision":"20100211.13","token":"%s"},'''
'''"parameters":{"type":"Songs","query":"%s"},"method":"getSearchResults"}''' % (self.session, self.uuid, self.getRequestToken("getSearchResults"), search_string.lower()))
self.response, self.result = http.request(self.search_url, 'POST', headers = header, body = data)
self.result = self.result
self.searchResults = json.loads(self.result)['result']
return self.searchResults
def songKeyfromID(self, id):
http = httplib2.Http()
self.songID = id
songKeyURL = ' http://cowbell.grooveshark.com/more.php?ge...FromSongID'
songKeyPOSTdata = ('''{"header":{"token":"%s","session":"%s","uuid":"%s","client":"gslite","clientRevision":"20100211.13"},'''
'''"parameters":{"songID":%s,"prefetch":false},"method":"getStreamKeyFromSongID"}''') % (self.getRequestToken("getStreamKeyFromSongID"), self.session, self.uuid, self.songID)
request, reply = http.request(songKeyURL, 'POST', headers = header, body = songKeyPOSTdata)
self.reply = json.loads(reply)['result']
self.songKey = self.reply['result']['streamKey']
return (self.songKey, self.reply['result']['streamServer'])
def download(self, songKey, streamServer):
http = httplib2.Http()
self.mp3URL = 'http://'+streamServer+'/stream.php'#use self. so that any outer program can access it (not local)
data = {}
data['streamKey'] = songKey
songHeader = dict(header)
songHeader['content-length'] = str(len(urllib.urlencode(data)))
songHeader['content-type'] = 'application/x-www-form-urlencoded'
self.response, self.song = http.request(self.mp3URL, 'POST', headers = songHeader, body = urllib.urlencode(data))
if self.response['status'] == '302':
self.response, self.song = http.request(self.response['location'], 'GET', headers = header)
if self.response['status'] == '400':
return '400 Error'
return self.song
def stream(self, streamKeys, songServers, file):
'''A list of streamkeys and base file'''
self.stream_process = subprocess.Popen('python stream.py %s %s %s' % (json.dumps(songServers), json.dumps(streamKeys), file))
def popular(self):
http = httplib2.Http()
url = 'http://cowbell.grooveshark.com/more.php?popularGetSongs'
popularPOSTdata = ('''{"header":{"token":"%s","session":"%s","uuid":"%s","client":"gslite","clientRevision":"20100211.13"},'''
'''"parameters":{},"method":"popularGetSongs"}''' % (self.getRequestToken("popularGetSongs"), self.session, self.uuid))
self.request, self.reply = http.request(url, 'POST', headers = header, body = popularPOSTdata)
return json.loads(self.reply)['result']['Songs']
# def favorites(self):
# http = httplib2.Http()
# url = 'http://cowbell.grooveshark.com/more.php?getFavorites'
# songKeyPOSTdata = ('''{"header":{"token":"%s","session":"%s","uuid":"%s","client":"gslite","clientRevision":"20091027.09"},'''
# '''"parameters":{"prefetch":false},"method":"getFavorites"}''' % (self.token, self.session, self.uuid))
# request, reply = http.request(url, 'POST', headers = header, body = songKeyPOSTdata)
# print request
# def playlist(self):
# http = httplib2.Http()
# url = 'http://cowbell.grooveshark.com/more.php?playlistGetSongs'
# songKeyPOSTdata = ('''{"header":{"token":"%s","session":"%s","uuid":"%s","client":"gslite","clientRevision":"20091027.09"},'''
# '''"parameters":{"prefetch":false},"method":"getPaylist"}''' % (self.token, self.session, self.uuid))
# request, reply = http.request(url, 'POST', headers = header, body = songKeyPOSTdata)
# print request
def setID3tags(self, file, title = None, artist = None, album = None, albumArt = None, genre = None, composer = None):
'''Does NOT WORK DUE TO UNKOWN UNICODE PROBLEM when saving'''
if not os.path.exists(file):
raise IOError('MP3 File does not exist.')
print file
tag_lookup = {'album':'TALB', 'comment':"COMM::'eng'", 'description':'TIT3', 'artist':'TPE1', 'title':'TIT2', 'track':'TRCK', 'composer':'TCOM', 'genre':'TCON'}
http = httplib2.Http()
request, albumArt = http.request('http://beta.grooveshark.com/static/amazonart/'+albumArt)
if request['status'] == '404':
albumArt = u''
tag_lookup['album_art'] = 'TART'
tags = {}
#tags['title'] = title
#tags['artist'] = artist
#tags['album'] = album
#tags['album_art'] = albumArt
tags['genre'] = genre
#tags['composer'] = composer
#if tags['composer'] == None:
# tags['composer'] = tags['artist']
for i in tags:
if tags[i] == None:
tags[i] = ''
audio = MP3(file)
#Delete Existing Songs
audio.delete()
#Set the tags
#Iterate through tags
for i in tags:
print i
print type(tags[i])
print tags[i]
audio[tag_lookup[i]] = tags[i]
print audio[tag_lookup[i]]
audio.tags.save()
#This is for streaming support
class Stream(urllib.FancyURLopener):
version = header['user-agent']
Great project!
Also, I have a semi-working obj-c/iPhone port if anyone is interested.