296 lines
7.6 KiB
Python
296 lines
7.6 KiB
Python
import urllib
|
|
import urllib2
|
|
#import pygtk
|
|
#pygtk.require('2.0')
|
|
import gtk
|
|
import webbrowser
|
|
import hashlib
|
|
import datetime
|
|
import time
|
|
import thread
|
|
|
|
from button import Button
|
|
|
|
#import xml.dom
|
|
from xml.dom import minidom
|
|
|
|
|
|
class Scrobbler(gtk.VBox):
|
|
def __init__(self,data):
|
|
gtk.VBox.__init__(self,False,0)
|
|
self.data = data
|
|
self.url = "http://ws.audioscrobbler.com/2.0/"
|
|
self.key = "2c76f85a6704efd74b5a358821284ef9"
|
|
self.secret = "3a6012bfb627b60a884cf33fc044885c"
|
|
self.token = ""
|
|
# Session ID
|
|
self.session = ""
|
|
# Now playing URL
|
|
self.npurl = ""
|
|
# Submission URL
|
|
self.suburl = ""
|
|
|
|
# Run these in new thread so we can keep loading other things while waiting
|
|
self.makegui()
|
|
#thread.start_new_thread(self.setup,("setup",None))
|
|
|
|
self.show()
|
|
|
|
|
|
def makegui(self):
|
|
if self.data.lfm == "":
|
|
uname = gtk.Label("Username:")
|
|
username = gtk.Entry()
|
|
passwd = gtk.Label("Password:")
|
|
password = gtk.Entry()
|
|
password.set_visibility(False)
|
|
|
|
username.connect("activate",self.fetchSession,username,uname,password,passwd)
|
|
password.connect("activate",self.fetchSession,username,uname,password,passwd)
|
|
|
|
uname.show()
|
|
username.show()
|
|
passwd.show()
|
|
password.show()
|
|
|
|
self.pack_start(uname,False,False,0)
|
|
self.pack_start(username,False,False,0)
|
|
self.pack_start(passwd,False,False,0)
|
|
self.pack_start(password,False,False,0)
|
|
else:
|
|
thread.start_new_thread(self.handshake,("",""))
|
|
#self.labels = [gtk.Label("")]*10
|
|
self.similar = []
|
|
for i in range(10):
|
|
label = gtk.Label(" ")
|
|
self.pack_start(label,False,False,0)
|
|
self.similar+=[label]
|
|
label.show()
|
|
|
|
|
|
def fetchSession(self,widgit,username,uname,password,passwd):
|
|
self.data.lfmuser = username.get_text().lower()
|
|
self.data.lfmpass = self.md5(password.get_text())
|
|
if self.data.lfmuser=="" or self.data.lfmpass=="":
|
|
return
|
|
else:
|
|
self.token = self.md5(self.data.lfmuser+self.data.lfmpass)
|
|
(url,list) = self.addMethod(self.url,"auth.getMobileSession")
|
|
(url,list) = self.addParam(url,list,"username",self.data.lfmuser)
|
|
(url,list) = self.addParam(url,list,"authToken",self.token)
|
|
(url,list) = self.addParam(url,list,"api_key",self.key)
|
|
(url,list) = self.addParam(url,list,"api_sig",self.getSig(list))
|
|
status = self.parseRequest(url)
|
|
attr = status.getAttributeNode("status")
|
|
if attr.value != "ok":
|
|
return
|
|
self.data.lfm = status.firstChild.nextSibling.firstChild.nextSibling.nextSibling.nextSibling.firstChild.data
|
|
username.hide()
|
|
uname.hide()
|
|
password.hide()
|
|
passwd.hide()
|
|
self.makegui()
|
|
|
|
|
|
def handshake(self,widgit,data):
|
|
#print "shaking hands"
|
|
url = "http://post.audioscrobbler.com/?hs=true"
|
|
list = [("hs","true")]
|
|
(url,list) = self.addParam(url,list,"p","1.2.1")
|
|
(url,list) = self.addParam(url,list,"c","tst")
|
|
(url,list) = self.addParam(url,list,"v","1.0")
|
|
(url,list) = self.addParam(url,list,"u",self.data.lfmuser)
|
|
tstp = self.timestamp()
|
|
(url,list) = self.addParam(url,list,"t",tstp)
|
|
(url,list) = self.addParam(url,list,"a",self.authToken(tstp))
|
|
(url,list) = self.addParam(url,list,"api_key",self.key)
|
|
status = self.placeRequest(url).readlines()
|
|
if status == None:
|
|
return
|
|
if status[0].strip() != "OK":
|
|
return
|
|
self.session = status[1].strip()
|
|
self.npurl = status[2].strip()#+"/?"
|
|
self.suburl = status[3].strip()#+"/?"
|
|
#for line in status:
|
|
# print line.strip()
|
|
|
|
|
|
def nowPlaying(self,info):
|
|
if self.data.lfm == "":
|
|
return
|
|
elif self.session == None:
|
|
self.handshake()
|
|
vals = {"s":self.session,
|
|
"a":info.artist.title(),
|
|
"t":info.title.title(),
|
|
"b":info.album.title(),
|
|
"l":str(info.duration),
|
|
"n":info.tnum,
|
|
"m":""}
|
|
|
|
data = urllib.urlencode(vals)
|
|
#status = self.placeRequest(url).readlines()
|
|
req = urllib2.Request(self.npurl,data)
|
|
req.add_header("User-Agent","Ocarina")
|
|
try:
|
|
status = urllib2.urlopen(req)
|
|
self.fetchSimilar(info.artist)
|
|
except:
|
|
return
|
|
#if status[0].strip() == "OK":
|
|
# print "Submission successful"
|
|
|
|
|
|
# Submit song and increment play count
|
|
# Playcount incremented if length < 30 seconds OR
|
|
# song played for > 240 seconds OR song played for > 1/2 total time
|
|
def submit(self,timestp):
|
|
if self.data.lfm == "":
|
|
return
|
|
elif self.session == None:
|
|
self.handshake()
|
|
info = self.data.song.info
|
|
if info.duration < 30:
|
|
info.count+=1
|
|
return
|
|
exit = True
|
|
if (self.data.song.position > 240):
|
|
exit = False
|
|
if self.data.song.position > (self.data.song.info.duration/2):
|
|
exit = False
|
|
|
|
if exit == True:
|
|
return
|
|
info.count+=1
|
|
vals = {"s":self.session,
|
|
"a[0]":info.artist.title(),
|
|
"t[0]":info.title.title(),
|
|
"i[0]":timestp,
|
|
"o[0]":"P",
|
|
"r[0]":"",
|
|
"l[0]":str(info.duration),
|
|
"b[0]":info.album.title(),
|
|
"n[0]":info.tnum,
|
|
"m[0]":""}
|
|
data = urllib.urlencode(vals)
|
|
req = urllib2.Request(self.suburl,data)
|
|
req.add_header("User-Agent","Ocarina")
|
|
try:
|
|
status = urllib2.urlopen(req)
|
|
except:
|
|
return
|
|
#for line in status:
|
|
# print line
|
|
#print status
|
|
|
|
|
|
# Fetch similar artists
|
|
def fetchSimilar(self,artist):
|
|
(url,list) = self.addMethod(self.url,"artist.getsimilar")
|
|
(url,list) = self.addParam(url,list,"artist",artist)
|
|
(url,list) = self.addParam(url,list,"limit","10")
|
|
(url,list) = self.addParam(url,list,"api_key",self.key)
|
|
status = self.parseRequest(url)
|
|
if status == None:
|
|
return
|
|
list = status.firstChild.nextSibling.childNodes
|
|
for i in range(list.length):
|
|
node = list.item(i)
|
|
if node.hasChildNodes()==True:
|
|
nameNode = node.firstChild.nextSibling.firstChild
|
|
self.similar[i/2].set_text(nameNode.data)
|
|
#for node in status.firstChild.childNodes:
|
|
# print node
|
|
|
|
|
|
# Retreive album art from last.fm
|
|
def fetchAlbumArt(self,artist,album,path):
|
|
if self.data.lfm == None:
|
|
return
|
|
if self.session == None:
|
|
self.handshake()
|
|
(url,list) = self.addMethod(self.url,"album.getInfo")
|
|
(url,list) = self.addParam(url,list,"artist",artist)
|
|
(url,list) = self.addParam(url,list,"album",album)
|
|
(url,list) = self.addParam(url,list,"api_key",self.key)
|
|
status = self.parseRequest(url)
|
|
if status == None:
|
|
return
|
|
list = status.childNodes
|
|
imgUrl = ""
|
|
for i in range(list.length):
|
|
items = list.item(i).childNodes
|
|
for node in items:
|
|
if node.hasChildNodes() == True:
|
|
if node.tagName == "image":
|
|
imgUrl = node.firstChild.data
|
|
|
|
if imgUrl:
|
|
try:
|
|
imgIn = urllib2.urlopen(imgUrl)
|
|
out = open(path,'w')
|
|
out.write(imgIn.read())
|
|
imgIn.close()
|
|
out.close()
|
|
except:
|
|
print "Error opening:",imgUrl
|
|
|
|
|
|
|
|
def authToken(self,t):
|
|
return self.md5(self.data.lfmpass+t)
|
|
|
|
|
|
def md5(self,string):
|
|
return hashlib.md5(string).hexdigest()
|
|
|
|
|
|
def timestamp(self):
|
|
now = datetime.datetime.now()
|
|
return str(int(time.mktime(now.timetuple())))
|
|
|
|
|
|
def addMethod(self,url,method):
|
|
return (self.url+"?method="+method,[("method",method)])
|
|
|
|
|
|
def addParam(self,url,list,param,val):
|
|
val = val.replace(" ","%20")
|
|
url+="&"+param+"="+val
|
|
if list:
|
|
list += [(param,val)]
|
|
return url,list
|
|
#return (url+"&"+param+"="+val,list+[(param,val)])
|
|
|
|
|
|
def getSig(self,list):
|
|
list.sort()
|
|
string = ""
|
|
for entry in list:
|
|
string+=entry[0]+entry[1]
|
|
#string = string + self.secret
|
|
return self.md5(string+self.secret)
|
|
#m = hashlib.md5(string)
|
|
#return m.hexdigest()
|
|
|
|
|
|
def placeRequest(self,url):
|
|
#print url
|
|
req = urllib2.Request(url)
|
|
req.add_header('User-Agent','Ocarina')
|
|
#return minidom.parse(urllib2.urlopen(req)).documentElement
|
|
try:
|
|
return urllib2.urlopen(req)
|
|
except:
|
|
return None
|
|
|
|
|
|
def parseRequest(self,url):
|
|
request = self.placeRequest(url)
|
|
if not (request == None):
|
|
return minidom.parse(request).documentElement
|
|
else:
|
|
return None
|
|
#return minidom.parse(self.placeRequest(url)).documentElement
|