forked from axiom-team/astrXbian
359 lines
14 KiB
Python
359 lines
14 KiB
Python
# 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) |