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