1 import urllib
, urllib2
, re
, xbmcplugin
, xbmcgui
, xbmc
, sys
, os
, time
4 __plugin__
= "Grooveshark"
5 __author__
= "Stephen Denham"
10 __XBMC_Revision__
= ""
13 MODE_SEARCH_ALBUMS
= 2
14 MODE_SEARCH_ARTISTS
= 3
24 MODE_SIMILAR_SONG
= 13
25 MODE_SIMILAR_ARTIST
= 14
34 resDir
= xbmc
.translatePath(os
.path
.join(os
.getcwd(), 'resources'))
35 libDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'lib'))
36 imgDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'img'))
37 thumbDir
= os
.path
.join('special://masterprofile/plugin_data/music', os
.path
.basename(os
.getcwd()))
39 sys
.path
.append (libDir
)
40 from GrooveAPI
import *
41 groovesharkApi
= GrooveAPI()
44 def __init__( self
, *args
, **kwargs
):
45 self
.__dict
__.update( kwargs
)
47 class 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" ]
53 def onPlayBackStopped(self
):
54 print "onPlayBackStopped"
56 if (not xbmc
.Player().isPlayingAudio()):
59 def onPlayBackEnded(self
):
60 print "onPlayBackEnded"
62 if (not xbmc
.Player().isPlayingAudio()):
65 def onPlayBackStarted(self
):
66 print "onPlayBackStarted"
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'))
77 songsearchlimit
= xbmcplugin
.getSetting('songsearchlimit')
78 albumsearchlimit
= xbmcplugin
.getSetting('albumsearchlimit')
79 artistsearchlimit
= xbmcplugin
.getSetting('artistsearchlimit')
81 musicplaylist
= xbmc
.PlayList(xbmc
.PLAYLIST_MUSIC
)
84 self
._handle
= int(sys
.argv
[1])
88 userid
= self
._get
_login
()
91 groovesharkApi
.setRemoveDuplicates(True)
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)
98 self
._add
_dir
('Favorites', '', MODE_FAVORITES
, self
.favoritesImg
, 0)
99 self
._add
_dir
('Playlists', '', MODE_PLAYLISTS
, self
.playlistImg
, 0)
101 def searchSongs(self
):
102 query
= self
._get
_keyboard
(default
="", heading
="Search songs")
104 songs
= groovesharkApi
.searchSongs(query
, limit
= xbmcplugin
.getSetting('songsearchlimit'))
106 self
._get
_songs
(songs
)
108 dialog
= xbmcgui
.Dialog()
109 dialog
.ok('Grooveshark', 'No matching songs.')
112 def searchAlbums(self
):
113 query
= self
._get
_keyboard
(default
="", heading
="Search albums")
115 albums
= groovesharkApi
.searchAlbums(query
, limit
= xbmcplugin
.getSetting('albumsearchlimit'))
116 if (len(albums
) > 0):
117 self
._get
_albums
(albums
)
119 dialog
= xbmcgui
.Dialog()
120 dialog
.ok('Grooveshark', 'No matching albums.')
123 def searchArtists(self
):
124 query
= self
._get
_keyboard
(default
="", heading
="Search artists")
126 artists
= groovesharkApi
.searchArtists(query
, limit
= xbmcplugin
.getSetting('artistsearchlimit'))
127 if (len(artists
) > 0):
128 self
._get
_artists
(artists
)
130 dialog
= xbmcgui
.Dialog()
131 dialog
.ok('Grooveshark', 'No matching artists.')
135 userid
= self
._get
_login
()
137 favorites
= groovesharkApi
.userGetFavoriteSongs(userid
)
138 if (len(favorites
) > 0):
139 self
._get
_songs
(favorites
)
141 dialog
= xbmcgui
.Dialog()
142 dialog
.ok('Grooveshark', 'You have no favorites.')
146 popular
= groovesharkApi
.popularGetSongs(limit
= xbmcplugin
.getSetting('songsearchlimit'))
147 if (len(popular
) > 0):
148 self
._get
_songs
(popular
)
150 dialog
= xbmcgui
.Dialog()
151 dialog
.ok('Grooveshark', 'No popular songs.')
155 userid
= self
._get
_login
()
157 playlists
= groovesharkApi
.userGetPlaylists()
158 if (len(playlists
) > 0):
159 self
._get
_playlists
(playlists
)
161 dialog
= xbmcgui
.Dialog()
162 dialog
.ok('Grooveshark', 'You have no playlists.')
165 def favorite(self
, songid
):
166 userid
= self
._get
_login
()
168 xbmc
.log("Favorite playSong: " + str(songid
))
169 groovesharkApi
.favoriteSong(songID
= songid
)
171 dialog
= xbmcgui
.Dialog()
172 dialog
.ok('Grooveshark', 'You must be logged in', 'to add favorites.')
174 def unfavorite(self
, songid
):
175 userid
= self
._get
_login
()
177 xbmc
.log("Unfavorite playSong: " + str(songid
))
178 groovesharkApi
.unfavoriteSong(songID
= songid
)
180 dialog
= xbmcgui
.Dialog()
181 dialog
.ok('Grooveshark', 'You must be logged in', 'to remove favorites.')
183 def frown(self
, songid
):
184 userid
= self
._get
_login
()
186 xbmc
.log("Frown playSong: " + str(songid
))
187 if groovesharkApi
.radioFrown(songId
= songid
) != True:
188 xbmc
.log("Unable to frown song " + str(songid
))
190 dialog
= xbmcgui
.Dialog()
191 dialog
.ok('Grooveshark', 'You must be logged in', 'to frown a song.')
193 def similarSong(self
, songid
):
194 userid
= self
._get
_login
()
196 xbmc
.log("Frown playSong: " + str(songid
))
197 if groovesharkApi
.radioSong(songId
= songid
) and groovesharkApi
.radioStartSongs() == True:
200 dialog
= xbmcgui
.Dialog()
201 dialog
.ok('Grooveshark', 'Cannot start radio')
203 dialog
= xbmcgui
.Dialog()
204 dialog
.ok('Grooveshark', 'You must be logged in', 'to update radio song.')
206 def similarArtist(self
, artistId
):
207 userid
= self
._get
_login
()
209 xbmc
.log("Add radio artist of playSong: " + str(artistId
))
210 if groovesharkApi
.radioArtist(artistId
= artistId
) and groovesharkApi
.radioStartArtists() == True:
213 dialog
= xbmcgui
.Dialog()
214 dialog
.ok('Grooveshark', 'Cannot start radio')
216 dialog
= xbmcgui
.Dialog()
217 dialog
.ok('Grooveshark', 'You must be logged in', 'to update radio artists.')
219 def album(self
,albumid
):
220 album
= groovesharkApi
.albumGetSongs(albumId
= albumid
, limit
= xbmcplugin
.getSetting('songsearchlimit'))
221 self
._get
_songs
(album
)
223 def artist(self
, artistid
):
224 albums
= groovesharkApi
.artistGetAlbums(artistId
= artistid
, limit
= xbmcplugin
.getSetting('albumsearchlimit'))
225 self
._get
_albums
(albums
)
227 def playlist(self
, playlistid
):
228 userid
= self
._get
_login
()
230 songs
= groovesharkApi
.playlistGetSongs(playlistId
= playlistid
, limit
= xbmcplugin
.getSetting('songsearchlimit'))
231 self
._get
_songs
(songs
)
233 dialog
= xbmcgui
.Dialog()
234 dialog
.ok('Grooveshark', 'You must be logged in', 'to get playlists.')
236 def playSong(self
, songItem
):
237 url
= songItem
.getProperty('url')
238 xbmc
.log("Playing: " + url
)
239 player
= GrovesharkPlayer(xbmc
.PLAYER_CORE_PAPLAYER
, function
=self
._add
_next
)
240 player
.play(url
, songItem
, False)
243 song
= self
._get
_next
()
247 def songItem(self
, url
, name
, album
, artist
, duration
, thumb
, image
):
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')
251 songItem
.setProperty('url', url
)
254 def _get_keyboard(self
, default
="", heading
="", hidden
=False):
255 kb
= xbmc
.Keyboard(default
, heading
, hidden
)
257 if (kb
.isConfirmed()):
258 return unicode(kb
.getText(), "utf-8")
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.')
269 if groovesharkApi
.loggedInStatus() == 1:
270 groovesharkApi
.logout()
271 userid
= groovesharkApi
.loginExt(username
, password
)
273 xbmc
.log("Logged in")
276 dialog
= xbmcgui
.Dialog()
277 dialog
.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
281 song
= groovesharkApi
.radioNextSong()[0]
283 url
= groovesharkApi
.getStreamURL(song
[1])
284 songImg
= self
._get
_thumb
(song
[9], str(song
[1]) + "-image")
287 songThm
= self
._get
_thumb
(song
[5], str(song
[1]) + "-thumb")
290 item
= self
.songItem(url
, song
[0], song
[3], song
[6], song
[2], songThm
, songImg
)
291 self
.musicplaylist
.add(url
, item
)
295 def _get_songs(self
, songs
):
296 xbmc
.log("Found " + str(len(songs
)) + " songs...")
298 while i
< len(songs
):
302 songDuration
= song
[2]
305 songArtistId
= song
[7]
308 songUrl
= groovesharkApi
.getStreamURL(songID
)
309 self
._add
_song
(songID
, songName
, songUrl
, songDuration
, songAlbum
, songArtist
, songArtistId
, songThumb
, songImage
)
311 xbmcplugin
.setContent(self
._handle
, 'songs')
313 def _get_albums(self
, albums
):
314 xbmc
.log("Found " + str(len(albums
)) + " albums...")
316 while i
< len(albums
):
318 albumArtistName
= album
[0]
321 albumImage
= album
[4]
322 self
._add
_dir
(albumName
+ " - " + albumArtistName
, '', MODE_ALBUM
, albumImage
, albumID
)
324 xbmcplugin
.setContent(self
._handle
, 'albums')
325 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ALBUM_IGNORE_THE
)
327 def _get_artists(self
, artists
):
328 xbmc
.log("Found " + str(len(artists
)) + " artists...")
330 while i
< len(artists
):
332 artistName
= artist
[0]
334 self
._add
_dir
(artistName
, '', MODE_ARTIST
, self
.artistImg
, artistID
)
336 xbmcplugin
.setContent(self
._handle
, 'artists')
337 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ARTIST_IGNORE_THE
)
339 def _get_playlists(self
, playlists
):
340 xbmc
.log("Found " + str(len(playlists
)) + " playlists...")
342 while i
< len(playlists
):
343 playlist
= playlists
[i
]
344 playlistName
= playlist
[0]
345 playlistID
= playlist
[1]
346 self
._add
_dir
(playlistName
, '', MODE_PLAYLIST
, self
.playlistImg
, playlistID
)
348 xbmcplugin
.setContent(self
._handle
, 'files')
349 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_PLAYLIST_ORDER
)
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'
356 if os
.path
.isfile(localThumb
) == False:
357 loc
= urllib
.URLopener()
358 loc
.retrieve(url
, localThumb
)
360 xbmc
.log('URL download failed of ' + url
+ ' to ' + localThumb
)
363 return os
.path
.join(os
.path
.join(thumbDir
, str(id))) + '.tbn'
365 def _add_song(self
, songid
, songname
, songurl
, songduration
, songalbum
, songartist
, songartistid
, songthumb
, songimage
):
366 songImg
= self
._get
_thumb
(songimage
, str(songid
) + "-image")
369 songThm
= self
._get
_thumb
(songthumb
, str(songid
) + "-thumb")
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
) \
375 +"&duration="+str(songduration
) \
376 +"&thumb="+urllib
.quote_plus(songThm
) \
377 +"&image="+urllib
.quote_plus(songImg
)
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
} )
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
)
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
)
386 menuItems
.append(("Grooveshark Favorite", "XBMC.RunPlugin("+fav
+")"))
387 menuItems
.append(("Not Grooveshark Favorite", "XBMC.RunPlugin("+unfav
+")"))
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
+")"))
391 songItem
.addContextMenuItems(menuItems
, replaceItems
=False)
392 xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=songItem
,isFolder
=False)
395 def _add_next(self
, stop
=0):
396 print "_add_next " + str(stop
)
398 groovesharkApi
.radioEnabled
= False
399 self
.playlist
.clear()
400 elif groovesharkApi
.radioTurnedOn() == True:
401 next
= self
._get
_next
()
402 self
.playlist
.add(url
, next
)
404 def _add_dir(self
, name
, url
, mode
, iconimage
, id):
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
)
407 dir.setInfo( type="Music", infoLabels
={ "title": name
} )
408 # Codes from http://xbmc-scripting.googlecode.com/svn/trunk/Script%20Templates/common/gui/codes.py
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)
417 paramstring
=sys
.argv
[2]
418 if len(paramstring
)>=2:
420 cleanedparams
=params
.replace('?','')
421 if (params
[len(params
)-1]=='/'):
422 params
=params
[0:len(params
)-2]
423 pairsofparams
=cleanedparams
.split('&')
425 for i
in range(len(pairsofparams
)):
427 splitparams
=pairsofparams
[i
].split('=')
428 if (len(splitparams
))==2:
429 param
[splitparams
[0]]=splitparams
[1]
433 grooveshark
= Groveshark();
441 try: url
=urllib
.unquote_plus(params
["url"])
443 try: name
=urllib
.unquote_plus(params
["name"])
445 try: mode
=int(params
["mode"])
447 try: id=int(params
["id"])
454 grooveshark
.categories()
456 elif mode
==MODE_SEARCH_SONGS
:
457 grooveshark
.searchSongs()
459 elif mode
==MODE_SEARCH_ALBUMS
:
460 grooveshark
.searchAlbums()
462 elif mode
==MODE_SEARCH_ARTISTS
:
463 grooveshark
.searchArtists()
465 elif mode
==MODE_POPULAR
:
466 grooveshark
.popular()
468 elif mode
==MODE_PLAYLISTS
:
469 grooveshark
.playlists()
471 elif mode
==MODE_FAVORITES
:
472 grooveshark
.favorites()
474 elif mode
==MODE_SONG
:
475 try: name
=urllib
.unquote_plus(params
["name"])
477 try: album
=urllib
.unquote_plus(params
["album"])
479 try: artist
=urllib
.unquote_plus(params
["artist"])
481 try: duration
=int(params
["duration"])
483 try: thumb
=urllib
.unquote_plus(params
["thumb"])
485 try: image
=urllib
.unquote_plus(params
["image"])
487 song
= grooveshark
.songItem(url
, name
, album
, artist
, duration
, thumb
, image
)
488 grooveshark
.playSong(song
)
490 elif mode
==MODE_ARTIST
:
491 grooveshark
.artist(lastID
)
493 elif mode
==MODE_ALBUM
:
494 grooveshark
.album(lastID
)
496 elif mode
==MODE_PLAYLIST
:
497 grooveshark
.playlist(lastID
)
499 elif mode
==MODE_FAVORITE
:
500 grooveshark
.favorite(lastID
)
502 elif mode
==MODE_UNFAVORITE
:
503 grooveshark
.unfavorite(lastID
)
505 elif mode
==MODE_SIMILAR_ARTIST
:
506 grooveshark
.similarArtist(lastID
)
508 elif mode
==MODE_SIMILAR_SONG
:
509 grooveshark
.similarSong(lastID
)
511 elif mode
==MODE_FROWN
:
512 grooveshark
.frown(lastID
)
514 if (mode
< MODE_SONG
):
515 xbmcplugin
.endOfDirectory(int(sys
.argv
[1]))