First attempt at dharma version.
[clinton/xbmc-groove.git] / default.py
CommitLineData
973b4c6c 1import urllib, urllib2, re, xbmcplugin, xbmcgui, xbmc, sys, os, time, pprint, shutil, xbmcaddon
8817bb2e 2
8817bb2e 3
4MODE_SEARCH_SONGS = 1
5MODE_SEARCH_ALBUMS = 2
6MODE_SEARCH_ARTISTS = 3
7MODE_POPULAR = 4
8MODE_FAVORITES = 5
9MODE_PLAYLISTS = 6
10MODE_ALBUM = 7
11MODE_ARTIST = 8
12MODE_PLAYLIST = 9
13MODE_SONG = 10
14MODE_FAVORITE = 11
15MODE_UNFAVORITE = 12
3fcef5ba 16MODE_SIMILAR_SONG = 13
17MODE_SIMILAR_ARTIST = 14
18MODE_FROWN = 15
8817bb2e 19
b738088f 20songsearchlimit = 0
21albumsearchlimit = 0
22artistsearchlimit = 0
8817bb2e 23
24lastID = 0
25
6ae708d0 26baseDir = os.getcwd()
27resDir = xbmc.translatePath(os.path.join(baseDir, 'resources'))
8817bb2e 28libDir = xbmc.translatePath(os.path.join(resDir, 'lib'))
29imgDir = xbmc.translatePath(os.path.join(resDir, 'img'))
973b4c6c 30thumbDir = os.path.join('special://masterprofile/addon_data/', os.path.join(os.path.basename(os.getcwd()), 'thumb'))
8817bb2e 31
32sys.path.append (libDir)
33from GrooveAPI import *
34groovesharkApi = GrooveAPI()
35
36class _Info:
37 def __init__( self, *args, **kwargs ):
38 self.__dict__.update( kwargs )
3fcef5ba 39
40class GrovesharkPlayer(xbmc.Player):
41 # Player Class: calls function when song changes or playback ends
42 def __init__(self, *args, **kwargs):
43 xbmc.Player.__init__(self)
44 self.function = kwargs[ "function" ]
45
46 def onPlayBackStopped(self):
47 print "onPlayBackStopped"
48 xbmc.sleep(300)
49 if (not xbmc.Player().isPlayingAudio()):
6ae708d0 50 self.function(0)
3fcef5ba 51
52 def onPlayBackEnded(self):
53 print "onPlayBackEnded"
54 xbmc.sleep(300)
55 if (not xbmc.Player().isPlayingAudio()):
6ae708d0 56 self.function(1)
57
3fcef5ba 58 def onPlayBackStarted(self):
59 print "onPlayBackStarted"
6ae708d0 60 self.function(2)
8817bb2e 61
62class Groveshark:
973b4c6c 63
64 settings = xbmcaddon.Addon(id='plugin.audio.groove')
8817bb2e 65
66 albumImg = xbmc.translatePath(os.path.join(imgDir, 'album.png'))
67 artistImg = xbmc.translatePath(os.path.join(imgDir, 'artist.png'))
68 favoritesImg = xbmc.translatePath(os.path.join(imgDir, 'favorites.png'))
69 playlistImg = xbmc.translatePath(os.path.join(imgDir, 'playlist.png'))
70 popularImg = xbmc.translatePath(os.path.join(imgDir, 'popular.png'))
71 songImg = xbmc.translatePath(os.path.join(imgDir, 'song.png'))
6ae708d0 72 defImg = xbmc.translatePath(os.path.join(imgDir, 'default.tbn'))
73 fanImg = xbmc.translatePath(os.path.join(baseDir, 'fanart.jpg'))
8817bb2e 74
973b4c6c 75 songsearchlimit = settings.getSetting('songsearchlimit')
76 albumsearchlimit = settings.getSetting('albumsearchlimit')
77 artistsearchlimit = settings.getSetting('artistsearchlimit')
6ae708d0 78
79
8817bb2e 80 def __init__( self ):
81 self._handle = int(sys.argv[1])
b738088f 82
8817bb2e 83 def categories(self):
b738088f 84
8817bb2e 85 userid = self._get_login()
b738088f 86
87 # Setup
88 groovesharkApi.setRemoveDuplicates(True)
6ae708d0 89 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
90 if os.path.isdir(thumbDir) == False:
91 os.makedirs(thumbDir)
92
3fcef5ba 93 self._add_dir('Search songs', '', MODE_SEARCH_SONGS, self.songImg, 0)
94 self._add_dir('Search albums', '', MODE_SEARCH_ALBUMS, self.albumImg, 0)
95 self._add_dir('Search artists', '', MODE_SEARCH_ARTISTS, self.artistImg, 0)
96 self._add_dir('Popular', '', MODE_POPULAR, self.popularImg, 0)
8817bb2e 97 if (userid != 0):
3fcef5ba 98 self._add_dir('Favorites', '', MODE_FAVORITES, self.favoritesImg, 0)
99 self._add_dir('Playlists', '', MODE_PLAYLISTS, self.playlistImg, 0)
100
8817bb2e 101 def searchSongs(self):
102 query = self._get_keyboard(default="", heading="Search songs")
103 if (query):
973b4c6c 104 songs = groovesharkApi.searchSongs(query, limit = self.settings.getSetting('songsearchlimit'))
8817bb2e 105 if (len(songs) > 0):
6ae708d0 106 self._add_songs_directory(songs)
8817bb2e 107 else:
108 dialog = xbmcgui.Dialog()
109 dialog.ok('Grooveshark', 'No matching songs.')
110 self.categories()
111
112 def searchAlbums(self):
113 query = self._get_keyboard(default="", heading="Search albums")
114 if (query):
973b4c6c 115 albums = groovesharkApi.searchAlbums(query, limit = self.settings.getSetting('albumsearchlimit'))
8817bb2e 116 if (len(albums) > 0):
6ae708d0 117 self._add_albums_directory(albums)
8817bb2e 118 else:
119 dialog = xbmcgui.Dialog()
120 dialog.ok('Grooveshark', 'No matching albums.')
121 self.categories()
122
123 def searchArtists(self):
124 query = self._get_keyboard(default="", heading="Search artists")
125 if (query):
973b4c6c 126 artists = groovesharkApi.searchArtists(query, limit = self.settings.getSetting('artistsearchlimit'))
8817bb2e 127 if (len(artists) > 0):
6ae708d0 128 self._add_artists_directory(artists)
8817bb2e 129 else:
130 dialog = xbmcgui.Dialog()
131 dialog.ok('Grooveshark', 'No matching artists.')
132 self.categories()
133
134 def favorites(self):
135 userid = self._get_login()
136 if (userid != 0):
137 favorites = groovesharkApi.userGetFavoriteSongs(userid)
138 if (len(favorites) > 0):
6ae708d0 139 self._add_songs_directory(favorites)
8817bb2e 140 else:
141 dialog = xbmcgui.Dialog()
142 dialog.ok('Grooveshark', 'You have no favorites.')
143 self.categories()
144
145 def popular(self):
973b4c6c 146 popular = groovesharkApi.popularGetSongs(limit = self.settings.getSetting('songsearchlimit'))
8817bb2e 147 if (len(popular) > 0):
6ae708d0 148 self._add_songs_directory(popular)
8817bb2e 149 else:
150 dialog = xbmcgui.Dialog()
151 dialog.ok('Grooveshark', 'No popular songs.')
152 self.categories()
153
154 def playlists(self):
155 userid = self._get_login()
156 if (userid != 0):
157 playlists = groovesharkApi.userGetPlaylists()
158 if (len(playlists) > 0):
6ae708d0 159 self._add_playlists_directory(playlists)
8817bb2e 160 else:
161 dialog = xbmcgui.Dialog()
162 dialog.ok('Grooveshark', 'You have no playlists.')
163 self.categories()
164
165 def favorite(self, songid):
166 userid = self._get_login()
167 if (userid != 0):
b738088f 168 xbmc.log("Favorite playSong: " + str(songid))
8817bb2e 169 groovesharkApi.favoriteSong(songID = songid)
170 else:
171 dialog = xbmcgui.Dialog()
172 dialog.ok('Grooveshark', 'You must be logged in', 'to add favorites.')
173
174 def unfavorite(self, songid):
175 userid = self._get_login()
176 if (userid != 0):
b738088f 177 xbmc.log("Unfavorite playSong: " + str(songid))
8817bb2e 178 groovesharkApi.unfavoriteSong(songID = songid)
179 else:
180 dialog = xbmcgui.Dialog()
181 dialog.ok('Grooveshark', 'You must be logged in', 'to remove favorites.')
3fcef5ba 182
183 def frown(self, songid):
184 userid = self._get_login()
185 if (userid != 0):
186 xbmc.log("Frown playSong: " + str(songid))
187 if groovesharkApi.radioFrown(songId = songid) != True:
188 xbmc.log("Unable to frown song " + str(songid))
189 else:
190 dialog = xbmcgui.Dialog()
191 dialog.ok('Grooveshark', 'You must be logged in', 'to frown a song.')
192
193 def similarSong(self, songid):
194 userid = self._get_login()
195 if (userid != 0):
196 xbmc.log("Frown playSong: " + str(songid))
197 if groovesharkApi.radioSong(songId = songid) and groovesharkApi.radioStartSongs() == True:
6ae708d0 198 self.playNext()
3fcef5ba 199 else:
200 dialog = xbmcgui.Dialog()
201 dialog.ok('Grooveshark', 'Cannot start radio')
202 else:
203 dialog = xbmcgui.Dialog()
204 dialog.ok('Grooveshark', 'You must be logged in', 'to update radio song.')
205
206 def similarArtist(self, artistId):
207 userid = self._get_login()
208 if (userid != 0):
209 xbmc.log("Add radio artist of playSong: " + str(artistId))
210 if groovesharkApi.radioArtist(artistId = artistId) and groovesharkApi.radioStartArtists() == True:
6ae708d0 211 self.playNext()
3fcef5ba 212 else:
213 dialog = xbmcgui.Dialog()
214 dialog.ok('Grooveshark', 'Cannot start radio')
215 else:
216 dialog = xbmcgui.Dialog()
217 dialog.ok('Grooveshark', 'You must be logged in', 'to update radio artists.')
8817bb2e 218
219 def album(self,albumid):
973b4c6c 220 album = groovesharkApi.albumGetSongs(albumId = albumid, limit = self.settings.getSetting('songsearchlimit'))
6ae708d0 221 self._add_songs_directory(album)
8817bb2e 222
223 def artist(self, artistid):
973b4c6c 224 albums = groovesharkApi.artistGetAlbums(artistId = artistid, limit = self.settings.getSetting('albumsearchlimit'))
6ae708d0 225 self._add_albums_directory(albums)
8817bb2e 226
227 def playlist(self, playlistid):
228 userid = self._get_login()
229 if (userid != 0):
973b4c6c 230 songs = groovesharkApi.playlistGetSongs(playlistId = playlistid, limit = self.settings.getSetting('songsearchlimit'))
6ae708d0 231 self._add_songs_directory(songs)
8817bb2e 232 else:
233 dialog = xbmcgui.Dialog()
234 dialog.ok('Grooveshark', 'You must be logged in', 'to get playlists.')
235
6ae708d0 236 def playSong(self, item):
237 url = item.getProperty('url')
9b1d8c96 238 xbmc.log("Playing: " + url)
973b4c6c 239 xbmc.Player( xbmc.PLAYER_CORE_PAPLAYER ).play(url, item)
3fcef5ba 240
6ae708d0 241 def playNext(self):
242 item = self._get_song_item(groovesharkApi.radioNextSong()[0])
243 url = item.getProperty('url')
244 self.player = GrovesharkPlayer(xbmc.PLAYER_CORE_PAPLAYER, function=self.onPlayBackChanged)
245 self.player.play(url, item)
973b4c6c 246 self.onPlayBackChanged(2)
6ae708d0 247
248 def songItem(self, id, name, album, artist, duration, thumb, image):
249 url = groovesharkApi.getStreamURL(id)
250 songImg = self._get_icon(image, str(id) + "-image")
251 print songImg
252 if songImg == "":
253 songImg = image
254 songThm = self._get_icon(thumb, str(id) + "-thumb")
255 if songThm == "":
256 songThm = thumb
257 item = xbmcgui.ListItem(label = artist + " - " + album + " - " + name, path=url, thumbnailImage=songThm, iconImage=songImg)
258 item.setInfo( type="Music", infoLabels={ "title": name, "duration": duration, "album": album, "artist": artist} )
259 item.setProperty('url', url)
260 item.setProperty('thumb', songThm)
261 item.setProperty('image', songImg)
262 item.setProperty('mimetype', 'audio/mpeg')
263 return item
8817bb2e 264
265 def _get_keyboard(self, default="", heading="", hidden=False):
266 kb = xbmc.Keyboard(default, heading, hidden)
267 kb.doModal()
268 if (kb.isConfirmed()):
269 return unicode(kb.getText(), "utf-8")
270 return ''
271
272 def _get_login(self):
973b4c6c 273 username = self.settings.getSetting('username')
274 password = self.settings.getSetting('password')
8817bb2e 275 if (username == "" or password == ""):
276 dialog = xbmcgui.Dialog()
277 dialog.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
278 return 0
279 else:
280 if groovesharkApi.loggedInStatus() == 1:
281 groovesharkApi.logout()
b738088f 282 userid = groovesharkApi.loginExt(username, password)
8817bb2e 283 if (userid != 0):
284 xbmc.log("Logged in")
285 return userid
286 else:
287 dialog = xbmcgui.Dialog()
288 dialog.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
289 return 0
290
6ae708d0 291 def _get_song_item(self, song):
292 name = song[0]
293 id = song[1]
294 duration = song[2]
295 album = song[3]
296 artist = song[6]
297 thumb = song[8]
298 image = song[9]
299 return self.songItem(id, name, album, artist, duration, thumb, image)
300
301 # File download
302 def _get_icon(self, url, id):
303 # Get the channel icon
304 localThumb = os.path.join(xbmc.translatePath(os.path.join(thumbDir, str(id)))) + '.tbn'
305 try:
306 if os.path.isfile(localThumb) == False:
307 loc = urllib.URLopener()
308 loc.retrieve(url, localThumb)
309 except:
310 xbmc.log('URL download failed of ' + url + ' to ' + localThumb)
311 try:
312 shutil.copyfile(self.defImg, localThumb)
313 except: pass
314 return ""
315
316 return os.path.join(os.path.join(thumbDir, str(id))) + '.tbn'
317
318 def _add_songs_directory(self, songs):
319 n = len(songs)
320 xbmc.log("Found " + str(n) + " songs...")
8817bb2e 321 i = 0
6ae708d0 322 while i < n:
8817bb2e 323 song = songs[i]
6ae708d0 324 item = self._get_song_item(song)
325 songurl = item.getProperty('url')
326 songthumb = item.getProperty('thumb')
327 songimage = item.getProperty('image')
328 songname = song[0]
329 songid = song[1]
330 songduration = song[2]
331 songalbum = song[3]
332 songartist = song[6]
333 songartistid = song[7]
334 u=sys.argv[0]+"?url="+urllib.quote_plus(songurl) \
335 +"&mode="+str(MODE_SONG)+"&name="+urllib.quote_plus(songname)+"&id=" \
336 +str(songid) \
337 +"&album="+urllib.quote_plus(songalbum) \
338 +"&artist="+urllib.quote_plus(songartist) \
339 +"&duration="+str(songduration) \
340 +"&thumb="+urllib.quote_plus(songthumb) \
341 +"&image="+urllib.quote_plus(songimage)
342 fav=sys.argv[0]+"?url="+urllib.quote_plus(songurl)+"&mode="+str(MODE_FAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
343 unfav=sys.argv[0]+"?url="+urllib.quote_plus(songurl)+"&mode="+str(MODE_UNFAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
344 similarArtist=sys.argv[0]+"?mode="+str(MODE_SIMILAR_ARTIST)+"&id="+str(songartistid)
345 similarSong=sys.argv[0]+"?mode="+str(MODE_SIMILAR_SONG)+"&id="+str(songid)
346 #frown=sys.argv[0]+"?mode="+str(MODE_FROWN)+"&id="+str(songid)
347 menuItems = []
348 menuItems.append(("Grooveshark Favorite", "XBMC.RunPlugin("+fav+")"))
349 menuItems.append(("Not Grooveshark Favorite", "XBMC.RunPlugin("+unfav+")"))
350 menuItems.append(("Listen to similar artist", "XBMC.RunPlugin("+similarArtist+")"))
351 menuItems.append(("Listen to similar song", "XBMC.RunPlugin("+similarSong+")"))
352 # menuItems.append(("No thanks!", "XBMC.RunPlugin("+frown+")"))
353 item.addContextMenuItems(menuItems, replaceItems=False)
354 xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False)
8817bb2e 355 i = i + 1
356 xbmcplugin.setContent(self._handle, 'songs')
8817bb2e 357
6ae708d0 358 def _add_albums_directory(self, albums):
8817bb2e 359 xbmc.log("Found " + str(len(albums)) + " albums...")
360 i = 0
361 while i < len(albums):
362 album = albums[i]
363 albumArtistName = album[0]
364 albumName = album[2]
365 albumID = album[3]
366 albumImage = album[4]
3fcef5ba 367 self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID)
8817bb2e 368 i = i + 1
369 xbmcplugin.setContent(self._handle, 'albums')
370 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE)
371
6ae708d0 372 def _add_artists_directory(self, artists):
8817bb2e 373 xbmc.log("Found " + str(len(artists)) + " artists...")
374 i = 0
375 while i < len(artists):
376 artist = artists[i]
377 artistName = artist[0]
378 artistID = artist[1]
3fcef5ba 379 self._add_dir(artistName, '', MODE_ARTIST, self.artistImg, artistID)
8817bb2e 380 i = i + 1
381 xbmcplugin.setContent(self._handle, 'artists')
382 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE)
383
6ae708d0 384 def _add_playlists_directory(self, playlists):
8817bb2e 385 xbmc.log("Found " + str(len(playlists)) + " playlists...")
386 i = 0
387 while i < len(playlists):
388 playlist = playlists[i]
389 playlistName = playlist[0]
390 playlistID = playlist[1]
3fcef5ba 391 self._add_dir(playlistName, '', MODE_PLAYLIST, self.playlistImg, playlistID)
8817bb2e 392 i = i + 1
393 xbmcplugin.setContent(self._handle, 'files')
394 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_PLAYLIST_ORDER)
3fcef5ba 395
396 def _add_dir(self, name, url, mode, iconimage, id):
8817bb2e 397 u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
398 dir=xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
b738088f 399 dir.setInfo( type="Music", infoLabels={ "title": name } )
8817bb2e 400 # Codes from http://xbmc-scripting.googlecode.com/svn/trunk/Script%20Templates/common/gui/codes.py
401 menuItems = []
402 menuItems.append(("Select", "XBMC.executebuiltin(Action(7))"))
403 dir.addContextMenuItems(menuItems, replaceItems=True)
404 return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=dir,isFolder=True)
6ae708d0 405
406 def onPlayBackChanged(self, change):
973b4c6c 407 xbmc.log("onPlayBackChanged " + str(change))
6ae708d0 408 if change == 0:
409 groovesharkApi.radioEnabled = False
6ae708d0 410 if change == 1 and groovesharkApi.radioTurnedOn() == True:
973b4c6c 411 xbmc.log("playnext")
6ae708d0 412 self.player.playNext()
973b4c6c 413 if change == 2:
414 xbmc.log("playback started")
415 xbmc.sleep(7500)
416 while self.player.isPlaying() or xbmc.Player(xbmc.PLAYER_CORE_PAPLAYER).isPlaying():
417 xbmc.sleep(1000)
418 xbmc.log("stopped playing")
6ae708d0 419
8817bb2e 420
421def get_params():
422 param=[]
423 paramstring=sys.argv[2]
424 if len(paramstring)>=2:
425 params=sys.argv[2]
426 cleanedparams=params.replace('?','')
427 if (params[len(params)-1]=='/'):
428 params=params[0:len(params)-2]
429 pairsofparams=cleanedparams.split('&')
430 param={}
431 for i in range(len(pairsofparams)):
432 splitparams={}
433 splitparams=pairsofparams[i].split('=')
434 if (len(splitparams))==2:
435 param[splitparams[0]]=splitparams[1]
436 print param
437 return param
438
439grooveshark = Groveshark();
440
441params=get_params()
442url=None
443name=None
444mode=None
445id=None
446
447try: url=urllib.unquote_plus(params["url"])
448except: pass
449try: name=urllib.unquote_plus(params["name"])
450except: pass
451try: mode=int(params["mode"])
452except: pass
453try: id=int(params["id"])
454except: pass
455
456if (id > 0):
457 lastID = id
458
459if mode==None:
460 grooveshark.categories()
461
462elif mode==MODE_SEARCH_SONGS:
463 grooveshark.searchSongs()
464
465elif mode==MODE_SEARCH_ALBUMS:
466 grooveshark.searchAlbums()
467
468elif mode==MODE_SEARCH_ARTISTS:
469 grooveshark.searchArtists()
470
471elif mode==MODE_POPULAR:
472 grooveshark.popular()
473
474elif mode==MODE_PLAYLISTS:
475 grooveshark.playlists()
476
477elif mode==MODE_FAVORITES:
478 grooveshark.favorites()
479
480elif mode==MODE_SONG:
481 try: name=urllib.unquote_plus(params["name"])
482 except: pass
483 try: album=urllib.unquote_plus(params["album"])
484 except: pass
485 try: artist=urllib.unquote_plus(params["artist"])
486 except: pass
487 try: duration=int(params["duration"])
488 except: pass
b738088f 489 try: thumb=urllib.unquote_plus(params["thumb"])
490 except: pass
491 try: image=urllib.unquote_plus(params["image"])
492 except: pass
6ae708d0 493 song = grooveshark.songItem(id, name, album, artist, duration, thumb, image)
3fcef5ba 494 grooveshark.playSong(song)
8817bb2e 495
496elif mode==MODE_ARTIST:
497 grooveshark.artist(lastID)
498
499elif mode==MODE_ALBUM:
500 grooveshark.album(lastID)
501
502elif mode==MODE_PLAYLIST:
503 grooveshark.playlist(lastID)
504
505elif mode==MODE_FAVORITE:
506 grooveshark.favorite(lastID)
507
508elif mode==MODE_UNFAVORITE:
509 grooveshark.unfavorite(lastID)
3fcef5ba 510
511elif mode==MODE_SIMILAR_ARTIST:
512 grooveshark.similarArtist(lastID)
513
514elif mode==MODE_SIMILAR_SONG:
515 grooveshark.similarSong(lastID)
516
517elif mode==MODE_FROWN:
518 grooveshark.frown(lastID)
8817bb2e 519
520if (mode < MODE_SONG):
521 xbmcplugin.endOfDirectory(int(sys.argv[1]))