summaryrefslogtreecommitdiff
path: root/plugin.audio.lastfmtube/default.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.audio.lastfmtube/default.py')
-rw-r--r--plugin.audio.lastfmtube/default.py359
1 files changed, 359 insertions, 0 deletions
diff --git a/plugin.audio.lastfmtube/default.py b/plugin.audio.lastfmtube/default.py
new file mode 100644
index 0000000..31912a3
--- /dev/null
+++ b/plugin.audio.lastfmtube/default.py
@@ -0,0 +1,359 @@
+# Copyright (C) 2016 Lunatixz
+#
+#
+# This file is part of LastFM Tube.
+#
+# LastFM Tube is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# LastFM Tube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with LastFM Tube. If not, see <http://www.gnu.org/licenses/>.
+# -*- coding: utf-8 -*-
+import os, sys, time, datetime, pylast, re
+import urllib, socket, json, collections, random
+import xbmc, xbmcgui, xbmcplugin, xbmcvfs, xbmcaddon
+
+from simplecache import use_cache, SimpleCache
+
+# Plugin Info
+ADDON_ID = 'plugin.audio.lastfmtube'
+REAL_SETTINGS = xbmcaddon.Addon(id=ADDON_ID)
+ADDON_NAME = REAL_SETTINGS.getAddonInfo('name')
+SETTINGS_LOC = REAL_SETTINGS.getAddonInfo('profile').decode('utf-8')
+ADDON_PATH = REAL_SETTINGS.getAddonInfo('path').decode('utf-8')
+ADDON_VERSION = REAL_SETTINGS.getAddonInfo('version')
+ICON = REAL_SETTINGS.getAddonInfo('icon')
+FANART = REAL_SETTINGS.getAddonInfo('fanart')
+
+## GLOBALS ##
+TIMEOUT = 15
+USER1 = REAL_SETTINGS.getSetting('USER1')
+PASS1 = REAL_SETTINGS.getSetting('PASS1')
+USER2 = REAL_SETTINGS.getSetting('USER2').replace('Enter Username','')
+PASS2 = REAL_SETTINGS.getSetting('PASS2').replace('Enter Password','')
+MEDIA_LIMIT= [25,50,100,250][int(REAL_SETTINGS.getSetting('MEDIA_LIMIT'))]
+RANDOM_PLAY= REAL_SETTINGS.getSetting('RANDOM_PLAY') == "true"
+YTURL = 'plugin://plugin.video.youtube/play/?video_id='
+YSSEARCH = 'plugin://plugin.video.youtube/kodion/search/query/?q=%s'
+DEBUG = REAL_SETTINGS.getSetting('Enable_Debugging') == 'true'
+API_KEY = REAL_SETTINGS.getSetting('LASTFM_APIKEY')
+API_SECRET = REAL_SETTINGS.getSetting('LASTFM_APISECRET')
+
+USERLST = []
+if len(USER1) > 0:
+ USERLST.append((USER1, '', 0, USER1,pylast.md5(PASS1)))
+if len(USER2) > 0:
+ USERLST.append((USER2, '', 0, USER2,pylast.md5(PASS2)))
+
+MENULST = (('Top Tracks' , '', 3),
+ ('Loved Tracks' , '', 4),
+ ('Recently Played', '', 2))
+
+def log(msg, level = xbmc.LOGDEBUG):
+ if DEBUG == True:
+ xbmc.log(ADDON_ID + '-' + ADDON_VERSION + '-' + stringify(msg), level)
+
+def convertString(string):
+ try:
+ string = unicode(string, "ascii")
+ except UnicodeError:
+ string = unicode(string, "utf-8")
+ else:
+ string = stringify(string)
+ return string
+
+def uni(string, encoding='utf-8'):
+ if isinstance(string, basestring):
+ if not isinstance(string, unicode):
+ string = unicode(string, encoding)
+ return string
+
+def ascii(string):
+ if isinstance(string, basestring):
+ if isinstance(string, unicode):
+ string = string.encode('ascii', 'ignore')
+ return string
+
+def utf(string):
+ if isinstance(string, basestring):
+ if not isinstance(string, unicode):
+ string = string.encode('utf-8', 'ignore')
+ return string
+
+def encodeString(string):
+ return ''.join(i for i in string.encode('utf8') if ord(i)<128)
+
+def stringify(string):
+ if isinstance(string, list):
+ string = stringify(string[0])
+ elif isinstance(string, (int, float, long, complex, bool)):
+ string = str(string)
+ if isinstance(string, basestring):
+ if not isinstance(string, unicode):
+ string = unicode(string, 'utf-8')
+ elif isinstance(string, unicode):
+ string = string.encode('ascii', 'ignore')
+ else:
+ string = string.encode('utf-8', 'ignore')
+ return string
+
+def getParams():
+ param=[]
+ if len(sys.argv[2])>=2:
+ params=sys.argv[2]
+ cleanedparams=params.replace('?','')
+ if (params[len(params)-1]=='/'):
+ params=params[0:len(params)-2]
+ pairsofparams=cleanedparams.split('&')
+ param={}
+ for i in range(len(pairsofparams)):
+ splitparams={}
+ splitparams=pairsofparams[i].split('=')
+ if (len(splitparams))==2:
+ param[splitparams[0]]=splitparams[1]
+ return param
+
+socket.setdefaulttimeout(TIMEOUT)
+class LastFMTube():
+ def __init__(self):
+ self.cache = SimpleCache()
+
+
+ def mainMenu(self):
+ for item in USERLST:
+ self.addDir(*item)
+
+
+ def browseMenu(self, user, pwd):
+ for item in MENULST:
+ print item
+ self.addDir(*item,**{'user':user,'pwd':pwd})
+
+
+ def sendJSON(self, command):
+ data = ''
+ try:
+ data = xbmc.executeJSONRPC(uni(command))
+ except UnicodeEncodeError:
+ data = xbmc.executeJSONRPC(ascii(command))
+ return data
+
+
+ def loadJson(self, string):
+ if len(string) == 0:
+ return {}
+ try:
+ return json.loads(uni(string))
+ except Exception,e:
+ return {}
+
+
+ def escapeDirJSON(self, dir_name):
+ mydir = uni(dir_name)
+ if (mydir.find(":")):
+ mydir = mydir.replace("\\", "\\\\")
+ return mydir
+
+
+ @use_cache(31)
+ def getDirectory(self, path, media='video', ignore='false', method='random', order='ascending', end=0, start=0, filter={}):
+ json_query = ('{"jsonrpc":"2.0","method":"Files.GetDirectory","params":{"directory":"%s","properties":["thumbnail","fanart","plot","duration","playcount"],"media":"%s","sort":{"ignorearticle":%s,"method":"%s","order":"%s"},"limits":{"end":%s,"start":%s}},"id":1}' % (self.escapeDirJSON(path), media, ignore, method, order, end, start))
+ json_response = self.sendJSON(json_query)
+ return self.loadJson(json_response)
+
+
+ def buildMenu(self, url, auto=False):
+ log('buildMenu, url = ' + url)
+ json_response = self.getDirectory(url)
+ if 'result' in json_response and(json_response['result'] != None) and 'files' in json_response['result']:
+ response = json_response['result']['files']
+ response = [response[random.randint(0,len(response)-1)]] if auto == True else response
+ for item in response:
+ label = encodeString(item.get('label',''))
+
+ if (item.get('filetype','') or '') == 'file':
+ url = item.get('file','')
+ infoLabels ={"label":label ,"title":label ,"plot":item.get('plot',''), "duration":(item.get('duration','') or 0), "playcount":(item.get('playcount','') or 0)}
+ infoArt ={"thumb":(item.get('thumbnail','') or ICON),"poster":(item.get('thumbnail','') or ICON),"fanart":(item.get('fanart','') or FANART)}
+ self.addLink(label, url, 9, infoList=infoLabels, infoArt=infoArt)
+
+
+ def getRecentTracks(self, user, pwd, auto=False, rand=False, limit=250):
+ """
+ Get list of recently played tracks
+ """
+ playList = []
+ playCount = 0
+ log('getRecentTracks, user = ' + user)
+ network = pylast.LastFMNetwork(api_key=API_KEY, api_secret=API_SECRET, username=user, password_hash=pwd)
+ if auto == False:
+ self.addDir('[B]Create Playlist (%d)[/B]'%MEDIA_LIMIT, '5', 5, user, pwd)
+ user = network.get_user(network.username)
+ for track in user.get_recent_tracks(limit=limit):
+ artist = track.track.get_artist().name
+ title = track.track.get_title()
+ artist = encodeString(artist)
+ title = encodeString(title)
+ name = ('{0!s} - {1!s}'.format(artist, title))
+ url = YSSEARCH%(name.replace(' ','%20'))
+ if auto == True:
+ if rand == True and random.choice([True,False]) == True:
+ continue
+ self.buildMenu(url, True)
+ playCount += 1
+ if playCount >= MEDIA_LIMIT:
+ break
+ else:
+ self.addDir(name, url, 1)
+
+
+ def getLovedTracks(self, user, pwd, auto=False, rand=False, limit=250):
+ """Returns this user's loved track"""
+ playList = []
+ playCount= 0
+ log('getPlaylists, user = ' + user)
+ network = pylast.LastFMNetwork(api_key=API_KEY, api_secret=API_SECRET, username=user, password_hash=pwd)
+ if auto == False:
+ self.addDir('[B]Create Playlist (%d)[/B]'%MEDIA_LIMIT, '7', 7, user, pwd)
+ user = network.get_user(network.username)
+ for loved in user.get_loved_tracks(limit=limit):
+ artist = loved.track.get_artist().name
+ title = loved.track.get_title()
+ artist = encodeString(artist)
+ title = encodeString(title)
+ name = ('{0!s} - {1!s}'.format(artist, title))
+ url = YSSEARCH%(name.replace(' ','%20'))
+ if auto == True:
+ #lazy method, won't result in MEDIA_LIMIT
+ if rand == True and random.choice([True,False]) == True:
+ continue
+ self.buildMenu(url, True)
+ playCount += 1
+ if playCount >= MEDIA_LIMIT:
+ break
+ else:
+ self.addDir(name, url, 1)
+
+
+ def getTopTracks(self, user, pwd, auto=False, rand=False):
+ """Returns the most played tracks as a sequence of TopItem objects."""
+ playList = []
+ playCount= 0
+ log('getTopTracks, user = ' + user)
+ network = pylast.LastFMNetwork(api_key=API_KEY, api_secret=API_SECRET, username=user, password_hash=pwd)
+ if auto == False:
+ self.addDir('[B]Create Playlist (%d)[/B]'%MEDIA_LIMIT, '6', 6, user, pwd)
+ user = network.get_user(network.username)
+ for top in user.get_top_tracks() :
+ name = encodeString(str(top.item))
+ url = YSSEARCH%(name.replace(' ','%20'))
+ if auto == True:
+ #lazy method, won't result in MEDIA_LIMIT
+ if rand == True and random.choice([True,False]) == True:
+ continue
+ self.buildMenu(url, True)
+ playCount += 1
+ if playCount >= MEDIA_LIMIT:
+ break
+ else:
+ self.addDir(name, url, 1)
+
+
+ def resolveURL(self, url):
+ log('resolveURL, url = ' + url)
+ if len(re.findall('http[s]?://www.youtube.com/watch', url)) > 0:
+ return YTURL + url.split('/watch?v=')[1]
+ elif len(re.findall('http[s]?://youtu.be/', url)) > 0:
+ return YTURL + url.split('/youtu.be/')[1]
+ return url
+
+
+ def playVideo(self, name, url):
+ log('playVideo')
+ liz=xbmcgui.ListItem(name, path=url)
+ liz.setProperty("IsPlayable","true")
+ xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, liz)
+
+
+ def addLink(self, name, u, mode, user='', pwd='', infoList=False, infoArt=False, total=0):
+ log('addLink, name = ' + name)
+ liz=xbmcgui.ListItem(name)
+ liz.setProperty('IsPlayable', 'true')
+ if infoList == False:
+ liz.setInfo( type="Video", infoLabels={"label":name,"title":name} )
+ else:
+ liz.setInfo(type="Video", infoLabels=infoList)
+
+ if infoArt == False:
+ liz.setArt({'thumb':ICON,'fanart':FANART})
+ else:
+ liz.setArt(infoArt)
+ u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&user="+urllib.quote_plus(user)+"&pwd="+str(pwd)
+ xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,totalItems=total)
+
+
+ def addDir(self, name, u, mode, user='', pwd='', infoList=False, infoArt=False):
+ log('addDir, name = ' + name)
+ liz=xbmcgui.ListItem(name)
+ liz.setProperty('IsPlayable', 'false')
+ if infoList == False:
+ liz.setInfo(type="Video", infoLabels={"label":name,"title":name})
+ else:
+ liz.setInfo(type="Video", infoLabels=infoList)
+ if infoArt == False:
+ liz.setArt({'thumb':ICON,'fanart':FANART})
+ else:
+ liz.setArt(infoArt)
+ u=sys.argv[0]+"?url="+urllib.quote_plus(u)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&user="+urllib.quote_plus(user)+"&pwd="+str(pwd)
+ xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=liz,isFolder=True)
+
+
+params=getParams()
+try:
+ url=urllib.unquote_plus(params["url"])
+except:
+ url=None
+try:
+ name=urllib.unquote_plus(params["name"])
+except:
+ name=None
+try:
+ user=urllib.unquote_plus(params["user"])
+except:
+ user=None
+try:
+ pwd=urllib.unquote_plus(params["pwd"])
+except:
+ pwd=None
+try:
+ mode=int(params["mode"])
+except:
+ mode=None
+
+log("Mode: "+str(mode))
+log("URL : "+str(url))
+log("Name: "+str(name))
+log("User: "+str(user))
+log("PWD : "+str(pwd))
+
+if mode==None: LastFMTube().mainMenu()
+elif mode == 0: LastFMTube().browseMenu(user, pwd)
+elif mode == 1: LastFMTube().buildMenu(url)
+elif mode == 2: LastFMTube().getRecentTracks(user, pwd)
+elif mode == 3: LastFMTube().getTopTracks(user, pwd)
+elif mode == 4: LastFMTube().getLovedTracks(user, pwd)
+elif mode == 5: LastFMTube().getRecentTracks(user, pwd, True, RANDOM_PLAY)
+elif mode == 6: LastFMTube().getTopTracks(user, pwd, True, RANDOM_PLAY)
+elif mode == 7: LastFMTube().getLovedTracks(user, pwd, True, RANDOM_PLAY)
+elif mode == 9: LastFMTube().playVideo(name, url)
+
+xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_NONE )
+xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_LABEL )
+xbmcplugin.endOfDirectory(int(sys.argv[1]),cacheToDisc=True) \ No newline at end of file