More radio implementation.
[clinton/xbmc-groove.git] / default.py
CommitLineData
3fcef5ba 1import urllib, urllib2, re, xbmcplugin, xbmcgui, xbmc, sys, os, time
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
b738088f 34resDir = xbmc.translatePath(os.path.join(os.getcwd(), 'resources'))
8817bb2e 35libDir = xbmc.translatePath(os.path.join(resDir, 'lib'))
36imgDir = xbmc.translatePath(os.path.join(resDir, 'img'))
9b1d8c96 37thumbDir = os.path.join('special://masterprofile/plugin_data/music', os.path.basename(os.getcwd()))
8817bb2e 38
39sys.path.append (libDir)
40from GrooveAPI import *
41groovesharkApi = GrooveAPI()
42
43class _Info:
44 def __init__( self, *args, **kwargs ):
45 self.__dict__.update( kwargs )
3fcef5ba 46
47class GrovesharkPlayer(xbmc.Player):
48 # Player Class: calls function when song changes or playback ends
49 def __init__(self, *args, **kwargs):
50 xbmc.Player.__init__(self)
51 self.function = kwargs[ "function" ]
52
53 def onPlayBackStopped(self):
54 print "onPlayBackStopped"
55 xbmc.sleep(300)
56 if (not xbmc.Player().isPlayingAudio()):
57 self.function(stop=1)
58
59 def onPlayBackEnded(self):
60 print "onPlayBackEnded"
61 xbmc.sleep(300)
62 if (not xbmc.Player().isPlayingAudio()):
63 self.function(stop=0)
64
65 def onPlayBackStarted(self):
66 print "onPlayBackStarted"
8817bb2e 67
68class Groveshark:
69
70 albumImg = xbmc.translatePath(os.path.join(imgDir, 'album.png'))
71 artistImg = xbmc.translatePath(os.path.join(imgDir, 'artist.png'))
72 favoritesImg = xbmc.translatePath(os.path.join(imgDir, 'favorites.png'))
73 playlistImg = xbmc.translatePath(os.path.join(imgDir, 'playlist.png'))
74 popularImg = xbmc.translatePath(os.path.join(imgDir, 'popular.png'))
75 songImg = xbmc.translatePath(os.path.join(imgDir, 'song.png'))
76
77 songsearchlimit = xbmcplugin.getSetting('songsearchlimit')
78 albumsearchlimit = xbmcplugin.getSetting('albumsearchlimit')
79 artistsearchlimit = xbmcplugin.getSetting('artistsearchlimit')
3fcef5ba 80
81 musicplaylist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
b738088f 82
8817bb2e 83 def __init__( self ):
84 self._handle = int(sys.argv[1])
b738088f 85
8817bb2e 86 def categories(self):
b738088f 87
8817bb2e 88 userid = self._get_login()
b738088f 89
90 # Setup
91 groovesharkApi.setRemoveDuplicates(True)
b738088f 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):
b738088f 104 songs = groovesharkApi.searchSongs(query, limit = xbmcplugin.getSetting('songsearchlimit'))
8817bb2e 105 if (len(songs) > 0):
106 self._get_songs(songs)
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):
b738088f 115 albums = groovesharkApi.searchAlbums(query, limit = xbmcplugin.getSetting('albumsearchlimit'))
8817bb2e 116 if (len(albums) > 0):
117 self._get_albums(albums)
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):
b738088f 126 artists = groovesharkApi.searchArtists(query, limit = xbmcplugin.getSetting('artistsearchlimit'))
8817bb2e 127 if (len(artists) > 0):
128 self._get_artists(artists)
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):
139 self._get_songs(favorites)
140 else:
141 dialog = xbmcgui.Dialog()
142 dialog.ok('Grooveshark', 'You have no favorites.')
143 self.categories()
144
145 def popular(self):
b738088f 146 popular = groovesharkApi.popularGetSongs(limit = xbmcplugin.getSetting('songsearchlimit'))
8817bb2e 147 if (len(popular) > 0):
148 self._get_songs(popular)
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):
159 self._get_playlists(playlists)
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:
198 self.playRadio()
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:
211 self.playRadio()
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):
b738088f 220 album = groovesharkApi.albumGetSongs(albumId = albumid, limit = xbmcplugin.getSetting('songsearchlimit'))
8817bb2e 221 self._get_songs(album)
222
223 def artist(self, artistid):
b738088f 224 albums = groovesharkApi.artistGetAlbums(artistId = artistid, limit = xbmcplugin.getSetting('albumsearchlimit'))
8817bb2e 225 self._get_albums(albums)
226
227 def playlist(self, playlistid):
228 userid = self._get_login()
229 if (userid != 0):
b738088f 230 songs = groovesharkApi.playlistGetSongs(playlistId = playlistid, limit = xbmcplugin.getSetting('songsearchlimit'))
8817bb2e 231 self._get_songs(songs)
232 else:
233 dialog = xbmcgui.Dialog()
234 dialog.ok('Grooveshark', 'You must be logged in', 'to get playlists.')
235
3fcef5ba 236 def playSong(self, songItem):
237 url = songItem.getProperty('url')
9b1d8c96 238 xbmc.log("Playing: " + url)
3fcef5ba 239 player = GrovesharkPlayer(xbmc.PLAYER_CORE_PAPLAYER, function=self._add_next)
240 player.play(url, songItem, False)
241
242 def playRadio(self):
243 song = self._get_next()
244 self._get_next()
245 self.playSong(song)
246
247 def songItem(self, url, name, album, artist, duration, thumb, image):
b738088f 248 songItem = xbmcgui.ListItem(label = name, path=url, thumbnailImage=thumb, iconImage=image)
249 songItem.setInfo( type="Music", infoLabels={ "title": name, "duration": duration, "album": album, "artist": artist} )
250 songItem.setProperty('mimetype', 'audio/mpeg')
3fcef5ba 251 songItem.setProperty('url', url)
252 return songItem
8817bb2e 253
254 def _get_keyboard(self, default="", heading="", hidden=False):
255 kb = xbmc.Keyboard(default, heading, hidden)
256 kb.doModal()
257 if (kb.isConfirmed()):
258 return unicode(kb.getText(), "utf-8")
259 return ''
260
261 def _get_login(self):
262 username = xbmcplugin.getSetting('username')
263 password = xbmcplugin.getSetting('password')
264 if (username == "" or password == ""):
265 dialog = xbmcgui.Dialog()
266 dialog.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
267 return 0
268 else:
269 if groovesharkApi.loggedInStatus() == 1:
270 groovesharkApi.logout()
b738088f 271 userid = groovesharkApi.loginExt(username, password)
8817bb2e 272 if (userid != 0):
273 xbmc.log("Logged in")
274 return userid
275 else:
276 dialog = xbmcgui.Dialog()
277 dialog.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
278 return 0
279
3fcef5ba 280 def _get_next(self):
281 song = groovesharkApi.radioNextSong()[0]
282 print song
283 url = groovesharkApi.getStreamURL(song[1])
284 songImg = self._get_thumb(song[9], str(song[1]) + "-image")
285 if songImg == "":
286 songImg = song[9]
287 songThm = self._get_thumb(song[5], str(song[1]) + "-thumb")
288 if songThm == "":
289 songThm = song[5]
290 item = self.songItem(url, song[0], song[3], song[6], song[2], songThm, songImg)
291 self.musicplaylist.add(url, item)
292 print item
293 return item
294
8817bb2e 295 def _get_songs(self, songs):
296 xbmc.log("Found " + str(len(songs)) + " songs...")
297 i = 0
298 while i < len(songs):
299 song = songs[i]
300 songName = song[0]
301 songID = song[1]
302 songDuration = song[2]
303 songAlbum = song[3]
304 songArtist = song[6]
3fcef5ba 305 songArtistId = song[7]
b738088f 306 songThumb = song[8]
8817bb2e 307 songImage = song[9]
b738088f 308 songUrl = groovesharkApi.getStreamURL(songID)
3fcef5ba 309 self._add_song(songID, songName, songUrl, songDuration, songAlbum, songArtist, songArtistId, songThumb, songImage)
8817bb2e 310 i = i + 1
311 xbmcplugin.setContent(self._handle, 'songs')
8817bb2e 312
313 def _get_albums(self, albums):
314 xbmc.log("Found " + str(len(albums)) + " albums...")
315 i = 0
316 while i < len(albums):
317 album = albums[i]
318 albumArtistName = album[0]
319 albumName = album[2]
320 albumID = album[3]
321 albumImage = album[4]
3fcef5ba 322 self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID)
8817bb2e 323 i = i + 1
324 xbmcplugin.setContent(self._handle, 'albums')
325 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE)
326
327 def _get_artists(self, artists):
328 xbmc.log("Found " + str(len(artists)) + " artists...")
329 i = 0
330 while i < len(artists):
331 artist = artists[i]
332 artistName = artist[0]
333 artistID = artist[1]
3fcef5ba 334 self._add_dir(artistName, '', MODE_ARTIST, self.artistImg, artistID)
8817bb2e 335 i = i + 1
336 xbmcplugin.setContent(self._handle, 'artists')
337 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE)
338
339 def _get_playlists(self, playlists):
340 xbmc.log("Found " + str(len(playlists)) + " playlists...")
341 i = 0
342 while i < len(playlists):
343 playlist = playlists[i]
344 playlistName = playlist[0]
345 playlistID = playlist[1]
3fcef5ba 346 self._add_dir(playlistName, '', MODE_PLAYLIST, self.playlistImg, playlistID)
8817bb2e 347 i = i + 1
348 xbmcplugin.setContent(self._handle, 'files')
349 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_PLAYLIST_ORDER)
350
3fcef5ba 351 # File download
352 def _get_thumb(self, url, id):
353 # Get the channel icon
354 localThumb = os.path.join(xbmc.translatePath(os.path.join(thumbDir, str(id)))) + '.tbn'
355 try:
356 if os.path.isfile(localThumb) == False:
357 loc = urllib.URLopener()
358 loc.retrieve(url, localThumb)
359 except:
360 xbmc.log('URL download failed of ' + url + ' to ' + localThumb)
361 return ""
362
363 return os.path.join(os.path.join(thumbDir, str(id))) + '.tbn'
364
365 def _add_song(self, songid, songname, songurl, songduration, songalbum, songartist, songartistid, songthumb, songimage):
366 songImg = self._get_thumb(songimage, str(songid) + "-image")
b738088f 367 if songImg == "":
368 songImg = songimage
3fcef5ba 369 songThm = self._get_thumb(songthumb, str(songid) + "-thumb")
b738088f 370 if songThm == "":
371 songThm = songthumb
8817bb2e 372 u=sys.argv[0]+"?url="+urllib.quote_plus(songurl)+"&mode="+str(MODE_SONG)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid) \
373 +"&album="+urllib.quote_plus(songalbum) \
374 +"&artist="+urllib.quote_plus(songartist) \
b738088f 375 +"&duration="+str(songduration) \
376 +"&thumb="+urllib.quote_plus(songThm) \
377 +"&image="+urllib.quote_plus(songImg)
b738088f 378 songItem = xbmcgui.ListItem(label = songartist + " - " + songalbum + " - " + songname, iconImage=songImg, thumbnailImage=songThm, path=songurl)
379 songItem.setInfo( type="Music", infoLabels={ "title": songname, "duration": songduration, "album": songalbum, "artist": songartist} )
8817bb2e 380 fav=sys.argv[0]+"?url="+urllib.quote_plus(songurl)+"&mode="+str(MODE_FAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
381 unfav=sys.argv[0]+"?url="+urllib.quote_plus(songurl)+"&mode="+str(MODE_UNFAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
3fcef5ba 382 similarArtist=sys.argv[0]+"?mode="+str(MODE_SIMILAR_ARTIST)+"&id="+str(songartistid)
383 similarSong=sys.argv[0]+"?mode="+str(MODE_SIMILAR_SONG)+"&id="+str(songid)
384 frown=sys.argv[0]+"?mode="+str(MODE_FROWN)+"&id="+str(songid)
8817bb2e 385 menuItems = []
3fcef5ba 386 menuItems.append(("Grooveshark Favorite", "XBMC.RunPlugin("+fav+")"))
8817bb2e 387 menuItems.append(("Not Grooveshark Favorite", "XBMC.RunPlugin("+unfav+")"))
3fcef5ba 388 menuItems.append(("Listen to similar artist", "XBMC.RunPlugin("+similarArtist+")"))
389 menuItems.append(("Listen to similar song", "XBMC.RunPlugin("+similarSong+")"))
390 menuItems.append(("No thanks!", "XBMC.RunPlugin("+frown+")"))
8817bb2e 391 songItem.addContextMenuItems(menuItems, replaceItems=False)
b738088f 392 xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=songItem,isFolder=False)
393 return songItem
8817bb2e 394
3fcef5ba 395 def _add_next(self, stop=0):
396 print "_add_next " + str(stop)
397 if stop == 1:
398 groovesharkApi.radioEnabled = False
399 self.playlist.clear()
400 elif groovesharkApi.radioTurnedOn() == True:
401 next = self._get_next()
402 self.playlist.add(url, next)
403
404 def _add_dir(self, name, url, mode, iconimage, id):
8817bb2e 405 u=sys.argv[0]+"?url="+urllib.quote_plus(url)+"&mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
406 dir=xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
b738088f 407 dir.setInfo( type="Music", infoLabels={ "title": name } )
8817bb2e 408 # Codes from http://xbmc-scripting.googlecode.com/svn/trunk/Script%20Templates/common/gui/codes.py
409 menuItems = []
410 menuItems.append(("Select", "XBMC.executebuiltin(Action(7))"))
411 dir.addContextMenuItems(menuItems, replaceItems=True)
412 return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=dir,isFolder=True)
b738088f 413
8817bb2e 414
415def get_params():
416 param=[]
417 paramstring=sys.argv[2]
418 if len(paramstring)>=2:
419 params=sys.argv[2]
420 cleanedparams=params.replace('?','')
421 if (params[len(params)-1]=='/'):
422 params=params[0:len(params)-2]
423 pairsofparams=cleanedparams.split('&')
424 param={}
425 for i in range(len(pairsofparams)):
426 splitparams={}
427 splitparams=pairsofparams[i].split('=')
428 if (len(splitparams))==2:
429 param[splitparams[0]]=splitparams[1]
430 print param
431 return param
432
433grooveshark = Groveshark();
434
435params=get_params()
436url=None
437name=None
438mode=None
439id=None
440
441try: url=urllib.unquote_plus(params["url"])
442except: pass
443try: name=urllib.unquote_plus(params["name"])
444except: pass
445try: mode=int(params["mode"])
446except: pass
447try: id=int(params["id"])
448except: pass
449
450if (id > 0):
451 lastID = id
452
453if mode==None:
454 grooveshark.categories()
455
456elif mode==MODE_SEARCH_SONGS:
457 grooveshark.searchSongs()
458
459elif mode==MODE_SEARCH_ALBUMS:
460 grooveshark.searchAlbums()
461
462elif mode==MODE_SEARCH_ARTISTS:
463 grooveshark.searchArtists()
464
465elif mode==MODE_POPULAR:
466 grooveshark.popular()
467
468elif mode==MODE_PLAYLISTS:
469 grooveshark.playlists()
470
471elif mode==MODE_FAVORITES:
472 grooveshark.favorites()
473
474elif mode==MODE_SONG:
475 try: name=urllib.unquote_plus(params["name"])
476 except: pass
477 try: album=urllib.unquote_plus(params["album"])
478 except: pass
479 try: artist=urllib.unquote_plus(params["artist"])
480 except: pass
481 try: duration=int(params["duration"])
482 except: pass
b738088f 483 try: thumb=urllib.unquote_plus(params["thumb"])
484 except: pass
485 try: image=urllib.unquote_plus(params["image"])
486 except: pass
3fcef5ba 487 song = grooveshark.songItem(url, name, album, artist, duration, thumb, image)
488 grooveshark.playSong(song)
8817bb2e 489
490elif mode==MODE_ARTIST:
491 grooveshark.artist(lastID)
492
493elif mode==MODE_ALBUM:
494 grooveshark.album(lastID)
495
496elif mode==MODE_PLAYLIST:
497 grooveshark.playlist(lastID)
498
499elif mode==MODE_FAVORITE:
500 grooveshark.favorite(lastID)
501
502elif mode==MODE_UNFAVORITE:
503 grooveshark.unfavorite(lastID)
3fcef5ba 504
505elif mode==MODE_SIMILAR_ARTIST:
506 grooveshark.similarArtist(lastID)
507
508elif mode==MODE_SIMILAR_SONG:
509 grooveshark.similarSong(lastID)
510
511elif mode==MODE_FROWN:
512 grooveshark.frown(lastID)
8817bb2e 513
514if (mode < MODE_SONG):
515 xbmcplugin.endOfDirectory(int(sys.argv[1]))