[RELEASE] Last.FM Playlist Generator Script - Auto Generate Similar Music Playlists

  Thread Rating:
  • 3 Votes - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Post Reply
gliko8 Offline
Junior Member
Posts: 23
Joined: Sep 2011
Reputation: 0
Post: #191
Hi,
I'v been very busy lately and couldn't get back to you on the Hebrew search issue.
i have checked the script with a friend and we managed to figure out the problem.
it seems that last.fm api cant query for tracks in hebrew, only artists.
we have add another loop to the script that checks for similar artists if similar tracks are return count=0:
PHP Code:
"""
    Script for generating smart playlists based on a seeding track and last.fm api
    Created by: ErlendSB
"""

import os
import random
import httplib
urlliburllib2
import sys
time
import threading
thread
import xbmc
xbmcguixbmcaddon
from urllib import quote_plus
unquote_plus
import re
from os
.path import exists
from os import remove
if sys.version_info < (27):
    
import simplejson
else:
    
import json as simplejson

__settings__ 
xbmcaddon.Addon(id='script.lastfmplaylistgeneratorPM')
__addonversion__ __settings__.getAddonInfo('version')
__cwd__          __settings__.getAddonInfo('path')

def log(message):
    
xbmc.log(msg=message)
class 
MyPlayerxbmc.Player ) :
    
countFoundTracks 0
    addedTracks 
= []
    
currentSeedingTrack 0
    firstRun 
0
    dbtype 
'sqlite3'
    
timeStarted time.time()
    
SCRIPT_NAME "LAST.FM Playlist Generator"
    
    
allowtrackrepeat =  __settings__.getSetting"allowtrackrepeat" )
    
preferdifferentartist __settings__.getSetting"preferdifferentartist" )
    
numberoftrackstoadd = ( 13510, )[ int__settings__.getSetting"numberoftrackstoadd" ) ) ]
    
delaybeforesearching= ( 21030, )[ int__settings__.getSetting"delaybeforesearching" ) ) ]
    
limitlastfmresult= ( 50100250, )[ int__settings__.getSetting"limitlastfmresult" ) ) ]
    
timer None


    
#apiPath = "http://ws.audioscrobbler.com/2.0/?api_key=71e468a84c1f40d4991ddccc46e40f1b"
    
apiPath "http://ws.audioscrobbler.com/2.0/?api_key=3ae834eee073c460a250ee08979184ec"
    
    
def __init__ self ):
        if 
not os.path.exists(xbmc.translatePath("special://userdata/advancedsettings.xml")):
            
self.dbtype 'sqlite3'
        
else:
            
from xml.etree.ElementTree import ElementTree
            advancedsettings 
ElementTree()
            
advancedsettings.parse(xbmc.translatePath("special://userdata/advancedsettings.xml"))
            
settings advancedsettings.getroot().find("musicdatabase")
            if 
settings is not None:
                for 
setting in settings:
                    if 
setting.tag == 'type':
                        
self.dbtype setting.text
            
else:
                
self.dbtype 'sqlite3'
        
xbmc.Player.__init__self )
        
xbmc.PlayList(0).clear()
        
self.firstRun 1
        BASE_RESOURCE_PATH 
os.path.join__cwd__"resources" )
        
process os.path.joinBASE_RESOURCE_PATH "pm.pid")
        
removeauto('lastfmplaylistgeneratorpm')
        
addauto("if os.path.exists('" os.path.normpath(process).replace('\\','\\\\') + "'):#lastfmplaylistgeneratorpm\n\tos.remove('" os.path.normpath(process).replace('\\','\\\\') + "')","lastfmplaylistgeneratorpm")
        
xbmc.executebuiltin("Notification(" self.SCRIPT_NAME+",Start by playing a song)")
    
    
def startPlayBack(self):
        print 
"[LFM PLG(PM)] onPlayBackStarted started"
        
if xbmc.Player().isPlayingAudio() == True:
            
currentlyPlayingTitle xbmc.Player().getMusicInfoTag().getTitle()
            print 
"[LFM PLG(PM)] " currentlyPlayingTitle " started playing"
                        
currentlyPlayingArtist xbmc.Player().getMusicInfoTag().getArtist()
            
self.countFoundTracks 0
            
if (self.firstRun == 1):
                
self.firstRun 0
                
#print "firstRun - clearing playlist"
                
album xbmc.Player().getMusicInfoTag().getAlbum()
                
cache_name xbmc.getCacheThumbName(os.path.dirname(xbmc.Player().getMusicInfoTag().getURL()))
                print 
"[LFM PLG(PM)] Playing file: %s" xbmc.Player().getMusicInfoTag().getURL()
                
thumb "special://profile/Thumbnails/Music/%s/%s" % ( cache_name[:1], cache_name, )
                
duration xbmc.Player().getMusicInfoTag().getDuration()
                
fanart ""
                
listitem self.getListItem(currentlyPlayingTitle,currentlyPlayingArtist,album,thumb,fanart,duration)
                
xbmc.PlayList(0).clear()
                
#xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Playlist.Clear", "params": { "playlistid": 0 }, "id": 1}')
                
xbmc.executebuiltin('XBMC.ActivateWindow(10500)')
                
xbmc.PlayList(0).add(urlxbmc.Player().getMusicInfoTag().getURL(), listitem listitem)
                
#trackPath = xbmc.Player().getMusicInfoTag().getURL()
                #xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "item": {"file": "%s"}, "playlistid": 0 }, "id": 1}' % trackPath)
                
self.addedTracks += [xbmc.Player().getMusicInfoTag().getURL()]
            
#print "Start looking for similar tracks"
            
self.fetch_similarTracks(currentlyPlayingTitle,currentlyPlayingArtist)

    
def onPlayBackStarted(self):
        print 
"[LFM PLG(PM)] onPlayBackStarted waiting:  " str(self.delaybeforesearching) +" seconds"
        
if (self.timer is not None and self.timer.isAlive()):
            
self.timer.cancel()
            
        
self.timer threading.Timer(self.delaybeforesearching,self.startPlayBack)
        
self.timer.start()

    
def fetch_similarTracksselfcurrentlyPlayingTitlecurrentlyPlayingArtist ):
        
apiMethod "&method=track.getsimilar&limit=" str(self.limitlastfmresult)

        
# The url in which to use
        
Base_URL self.apiPath apiMethod "&artist=" urllib.quote_plus(currentlyPlayingArtist) + "&track=" urllib.quote_plus(currentlyPlayingTitle)
        print 
Base_URL
        WebSock 
urllib.urlopen(Base_URL)  # Opens a 'Socket' to URL
        
WebHTML WebSock.read()            # Reads Contents of URL and saves to Variable
        
WebSock.close()                     # Closes connection to url
        #xbmc.executehttpapi("setresponseformat(openRecordSet;<recordset>;closeRecordSet;</recordset>;openRecord;<record>;closeRecord;</record>;openField;<field>;closeField;</field>)");
        #print WebHTML
        
similarTracks re.findall("<track>.+?<name>(.+?)</name>.+?<match>(.+?)</match>.+?<artist>.+?<name>(.+?)</name>.+?</artist>.+?</track>"WebHTMLre.DOTALL )
        
random.shuffle(similarTracks)
        
foundArtists = []
        
countTracks len(similarTracks)
        print 
"[LFM PLG(PM)] Count: " str(countTracks)
        if 
countTracks==0:
            
apiMethod "&method=artist.getsimilar&limit=" str(self.limitlastfmresult)
            
Base_URL self.apiPath apiMethod "&artist=" urllib.quote_plus(currentlyPlayingArtist)
                    print 
Base_URL
                    WebSock 
urllib.urlopen(Base_URL)  # Opens a 'Socket' to URL
                    
WebHTML WebSock.read()            # Reads Contents of URL and saves to Variable
                    
WebSock.close()
            
similarArtists re.findall("<artist>.+?<name>(.+?)</name>.+?</artist>"WebHTMLre.DOTALL)
            
#random.shuffle(similarArtists)
            
countArtists len(similarArtists)
            print 
"[LFM PLG(PM)] Artists Count: " str(countArtists)
            for 
artist in similarArtists:
                
json_query xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "properties": ["title", "artist", "album", "file", "thumbnail", "duration", "fanart"], "limits": {"end":1}, "sort": {"method":"random"}, "filter": {"field":"artist","operator":"contains","value":"%s"} } , "id": 1}' % (artist))
                
json_query unicode(json_query'utf-8'errors='ignore')
                
json_response simplejson.loads(json_query)
                if 
json_response.has_key('result') and json_response['result'] != None and json_response['result'].has_key('songs'):
                                    
count 0
                                    
for item in json_response['result']['songs']:
                        
count += 1
                        artist 
item["artist"]
                                            
trackTitle item["title"]
                                            
album item["album"]
                                            
trackPath item["file"]
                                            
thumb item["thumbnail"]
                                            
duration int(item["duration"])
                                            
fanart item["fanart"]
                                            
#log("[LFM PLG(PM)] Found: " + str(trackTitle) + " by: " + str(artist))
                                            
if ((self.allowtrackrepeat == "true" or self.allowtrackrepeat == 1) or (trackPath not in self.addedTracks)):
                                                    if ((
self.preferdifferentartist != "true" and self.preferdifferentartist != 1) or (eval(matchValue) < 0.2 and similarArtistName not in foundArtists)):
                                                            
listitem self.getListItem(trackTitle,artist,album,thumb,fanart,duration)
                                                            
xbmc.PlayList(0).add(url=trackPathlistitem=listitem)
                                                            
#xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "item": {"file": "%s"}, "playlistid": 0 }, "id": 1}' % trackPath)
                                                            
self.addedTracks += [trackPath]
                                                            
xbmc.executebuiltin("Container.Refresh")
                                                            
self.countFoundTracks += 1
                                                            
if (artist not in foundArtists):
                                                                    
foundArtists += [artist]
    
                                    if (
self.countFoundTracks >= self.numberoftrackstoadd):
                        break
                
#for artist in similarArtists:
                #print artist
        
for similarTrackNamematchValuesimilarArtistName in similarTracks:
            
#print "Looking for: " + similarTrackName + " - " + similarArtistName + " - " + matchValue
            
similarTrackName similarTrackName.replace("+"," ").replace("("," ").replace(")"," ").replace("&quot","''").replace("'","''").replace("&amp;","and")
            
similarArtistName similarArtistName.replace("+"," ").replace("("," ").replace(")"," ").replace("&quot","''").replace("'","''").replace("&amp;","and")
            
json_query xbmc.executeJSONRPC('{"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}' % (similarTrackNamesimilarArtistName)) 
            
json_query unicode(json_query'utf-8'errors='ignore')
            
json_response simplejson.loads(json_query)
            
# separate the records
            
if json_response.has_key('result') and json_response['result'] != None and json_response['result'].has_key('songs'):
                
count 0
                
for item in json_response['result']['songs']:
                    
count += 1
                    artist 
item["artist"]
                    
trackTitle item["title"]
                    
album item["album"]
                    
trackPath item["file"]
                    
thumb item["thumbnail"]
                    
duration int(item["duration"])
                    
fanart item["fanart"]
                    
log("[LFM PLG(PM)] Found: " str(trackTitle) + " by: " str(artist))
                    if ((
self.allowtrackrepeat == "true" or self.allowtrackrepeat == 1) or (trackPath not in self.addedTracks)):
                        if ((
self.preferdifferentartist != "true" and self.preferdifferentartist != 1) or (eval(matchValue) < 0.2 and similarArtistName not in foundArtists)):
                            
listitem self.getListItem(trackTitle,artist,album,thumb,fanart,duration)
                            
xbmc.PlayList(0).add(url=trackPathlistitem=listitem)
                            
#xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "Playlist.Add", "params": { "item": {"file": "%s"}, "playlistid": 0 }, "id": 1}' % trackPath)
                            
self.addedTracks += [trackPath]
                            
xbmc.executebuiltin("Container.Refresh")
                            
self.countFoundTracks += 1
                            
if (similarArtistName not in foundArtists):
                                
foundArtists += [similarArtistName]

                if (
self.countFoundTracks >= self.numberoftrackstoadd):
                    break
            
        if (
self.countFoundTracks == 0):
            
time.sleep(3)
            
#self.firstRun = 1
            
log("[LFM PLG(PM)] None found")
            
xbmc.executebuiltin("Notification(" self.SCRIPT_NAME+",No similar tracks were found)")
            return 
False
            
        xbmc
.executebuiltin('SetCurrentPlaylist(0)')
        
    
def getListItem(selftrackTitleartistalbumthumbfanart,duration):
        
listitem xbmcgui.ListItem(trackTitle)
        if (
fanart == ""):
            
cache_name xbmc.getCacheThumbNamestr(artist) )
            
fanart "special://profile/Thumbnails/Music/%s/%s" % ( "Fanart"cache_name, )
        
listitem.setProperty('fanart_image',fanart)
        
listitem.setInfo('music', { 'title'trackTitle'artist'artist'album'album'duration'duration })
        
listitem.setThumbnailImage(thumb)
        
#log("[LFM PLG(PM)] Fanart:%s" % fanart)
        
return listitem

def addauto
(newentryscriptcode):
    
autoexecfile xbmc.translatePath('special://home/userdata/autoexec.py')
    
#autoexecfile = "special://masterprofile/autoexec.py"
    
if exists(autoexecfile):
        
fh open(autoexecfile)
        
lines = []
        for 
line in fh.readlines():
            
lines.append(line)
        
lines.append("import time" "#" scriptcode "\n")
        
lines.append("time.sleep(2)" "#" scriptcode "\n")
        
lines.append(newentry "#" scriptcode "\n")
        
fh.close()
        
open(autoexecfile"w")
        if 
not "import xbmc\n" in lines:
            
f.write("import xbmc" "#" scriptcode "\n")
        if 
not "import os\n" in lines:
            
f.write("import os" "#" scriptcode "\n")
        
f.writelines(lines)
        
f.close()
    else:
        
open(autoexecfile"w")
        
f.write("import time" "#" scriptcode "\n")
        
f.write("time.sleep(2)" "#" scriptcode "\n")
        
f.write("import os" "#" scriptcode "\n")
        
f.write("import xbmc" "#" scriptcode "\n")
        
f.write(newentry "#" scriptcode "\n")
        
f.close()

def removeauto(scriptcode):
    
autoexecfile xbmc.translatePath('special://home/userdata/autoexec.py')
    
#autoexecfile = "special://masterprofile/autoexec.py"
    
if exists(autoexecfile):
        
fh open(autoexecfile)
        
lines = [ line for line in fh if not line.strip().endswith("#" scriptcode) ]
        
fh.close()
        
open(autoexecfile"w")
        
f.writelines(lines)
        
f.close()
        
BASE_RESOURCE_PATH os.path.join__cwd__"resources" )

process os.path.joinBASE_RESOURCE_PATH "pm.pid")
p=MyPlayer()
while(
1):
    if 
os.path.exists(process):
        if (
xbmc.abortRequested):
            
os.remove(process)
            print 
"[LFM PLG(PM)] deleting pid"
        
xbmc.sleep(500)
    else:
        break 
find quote
Post Reply