2013-02-15, 01:46
Hey,
in the course of making a little home automation system, i stumbled upon
ErlendSB's great LastFM PlaylistGenerator which is awesome as an addon;
But didn't quite suite my needs. So is decided to make my own little Python
Script that runs seperately and populates (on request) the Playlist. This is just
a quick and dirty script, and is heavily based on ErlendSB's addon. So all credit
to him.
Should be pretty much self explaining and functioning (IF control from remotes is
enabled in XBMC.
Hope I have not made any mistakes and/or offended someone
Cheers
in the course of making a little home automation system, i stumbled upon
ErlendSB's great LastFM PlaylistGenerator which is awesome as an addon;
But didn't quite suite my needs. So is decided to make my own little Python
Script that runs seperately and populates (on request) the Playlist. This is just
a quick and dirty script, and is heavily based on ErlendSB's addon. So all credit
to him.
PHP Code:
import os
import json
import socket
import re
import urllib
#for debug
from pprint import pprint
class LastFMPlaylist():
def __init__ (self):
self.delay = 5
self.add_limit = 10
self.search_limit = 240
self.api = "http://ws.audioscrobbler.com/2.0/?api_key=3ae834eee073c460a250ee08979184ec"
self.allAddedSongs = []
self.timer = None
self.artist = "Not working"
self.title = "Hallo"
self.newSongs = []
def startTitleSearch(self):
'''Gets currently Played Song from XBMC'''
jdata ='{"jsonrpc": "2.0", "method": "Player.GetItem", "params": { "properties": ["title","artist"], "playerid": 0 }, "id": "AudioGetItem"}'
decoded = self.getJson(jdata)
print "Currently Playing Song is " + decoded['result']['item']['artist'][0] + ' - ' + decoded['result']['item']['title']
self.artist = decoded['result']['item']['artist'][0]
self.title = decoded['result']['item']['title']
answer = self.dumbUnavailable(self.fetchSimilarTracks(self.artist,self.title))
self.allAddedSongs += answer
print len(self.allAddedSongs)
def fetchSimilarTracks(self, artist,title):
'''Gets similar Artists Song'''
apiMethod = "&method=track.getsimilar&limit=" + str(self.search_limit)
urla = urllib.quote_plus(artist)
urlt = urllib.quote_plus(title)
# The url in which to use
apiurl = self.api + apiMethod + "&artist=" + urla + "&track=" + urlt
print "Search on " + apiurl
# Gets Info from LASTFM
WebSock = urllib.urlopen(apiurl) # Opens a 'Socket' to URL
WebHTML = WebSock.read() # Reads Contents of URL and saves to Variable
WebSock.close() # Closes connection to url
print "Search Done"
# Gets Array with [ TRACK, MATCHVALUE, ARTIST]
similarTracks = re.findall("<track>.+?<name>(.+?)</name>.+?<match>(.+?)</match>.+?<artist>.+?<name>(.+?)</name>.+?</artist>.+?</track>", WebHTML, re.DOTALL )
return similarTracks
def checkWanted(self, artist, title,matchValue,album,duration):
'''Check for Wanted Status SHOULD RETURN FALSE IF NOT MET '''
# CAN BE PRETTY MUCH ANY CRITERIA YOU WANT
if matchValue <= 0.00005:
return False
# CHECKS AGAINST ALREADY ADDED SONGS
for item in self.allAddedSongs:
if item[0] == artist and item[1] == title: # IS EQUAL TO NOT THE SAME SONG AGAIN
return False
return True
def printPlaylist(self):
print "Added Songs: "
for item in self.allAddedSongs:
print item[0] + " - " + item[1]
print " "
print "Total Songs Added: " + str(len(self.allAddedSongs))
def addToPlaylist(self):
for item in self.newSongs :
addRequest = '{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "item": {"file": "' + item[3] + '"}, "playlistid": 0 }, "id": 1}'
#addRequest = '{ "jsonrpc": "2.0", "method": "JSONRPC.Introspect", "params": { "filter": { "id": "Playlist.Add", "type": "method" } }, "id": 1 }'
self.getJson(addRequest)
def getJson(self,string):
gsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = gsocket.connect(("localhost", 9090))
# Whatever structure you need to send goes here:
#jdata = json.dumps({"username":"...", "password":"..."})
gsocket.send(string)
response = gsocket.recv(2048)
json_query = unicode(response, 'utf-8', errors='ignore')
json_response = json.loads(json_query)
return json_response
def dumbUnavailable (self, similarTracks):
songsAdded = 0
songsToAdd = []
# Shuffles the Result
random.shuffle(similarTracks)
for track, matchValue, artist in similarTracks:
track = track.replace("+"," ").replace("("," ").replace(")"," ").replace(""","''").replace("'","''").replace("&","and")
artist = artist.replace("+"," ").replace("("," ").replace(")"," ").replace(""","''").replace("'","''").replace("&","and")
#Query LastFM for TRACK
json_response = self.getJson('{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": ["title", "artist", "album", "file", "thumbnail", "duration", "fanart"], "limits": {"end":1}, "sort": {"method":"random"}, "filter": { "and":[{"field":"title","operator":"contains","value":"%s"},{"field":"artist","operator":"contains","value":"%s"}] } }, "id": 1}' % (track, artist))
# separate the records
if json_response.has_key('result') and json_response['result'] != None and json_response['result'].has_key('songs'):
nur = 0
for item in json_response['result']['songs']:
artist = item["artist"][0]
trackTitle = item["title"]
album = item["album"]
trackPath = item["file"]
thumb = item["thumbnail"]
duration = int(item["duration"])
fanart = item["fanart"]
if (self.checkWanted(artist,trackTitle,matchValue,album,duration) != False or nur != 0):
songsToAdd.append([artist,trackTitle,album,trackPath,thumb,duration,fanart]) #if file is wanted add to list
songsAdded += 1
nur += 1
if (songsAdded >= self.add_limit):
break
self.newSongs = songsToAdd
return songsToAdd
p = LastFMPlaylist()
p.startTitleSearch()
p.printPlaylist()
p.addToPlaylist()
Should be pretty much self explaining and functioning (IF control from remotes is
enabled in XBMC.
Hope I have not made any mistakes and/or offended someone
Cheers