1 import urllib
, sys
, os
, shutil
, re
, time
, xbmcaddon
, xbmcplugin
, xbmcgui
, xbmc
, pickle
4 MODE_SEARCH_ARTISTS
= 3
5 MODE_SEARCH_ARTISTS_ALBUMS
= 4
6 MODE_SEARCH_PLAYLISTS
= 5
7 MODE_ARTIST_POPULAR
= 6
23 ACTION_SELECT_ITEM
= 7
24 ACTION_PREVIOUS_MENU
= 10
26 # Formats for track labels
27 ARTIST_ALBUM_NAME_LABEL
= 0
28 NAME_ALBUM_ARTIST_LABEL
= 1
31 resDir
= xbmc
.translatePath(os
.path
.join(baseDir
, 'resources'))
32 libDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'lib'))
33 imgDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'img'))
34 cacheDir
= os
.path
.join(xbmc
.translatePath('special://masterprofile/addon_data/'), os
.path
.basename(os
.getcwd()))
35 thumbDirName
= 'thumb'
36 thumbDir
= os
.path
.join('special://masterprofile/addon_data/', os
.path
.basename(os
.getcwd()), thumbDirName
)
38 baseModeUrl
= 'plugin://plugin.audio.groove/'
39 playlistUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLIST
)
40 playlistsUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLISTS
)
41 favoritesUrl
= baseModeUrl
+ '?mode=' + str(MODE_FAVORITES
)
43 searchArtistsAlbumsName
= "Search for artist's albums..."
45 thumbDef
= os
.path
.join(imgDir
, 'default.tbn')
47 sys
.path
.append (libDir
)
48 from GroovesharkAPI
import GrooveAPI
51 groovesharkApi
= GrooveAPI()
52 if groovesharkApi
.pingService() != True:
53 raise StandardError('No Grooveshark service')
55 dialog
= xbmcgui
.Dialog()
56 dialog
.ok('Grooveshark XBMC', 'Unable to connect with Grooveshark.', 'Please try again later')
61 def __init__( self
, *args
, **kwargs
):
62 self
.__dict
__.update( kwargs
)
67 albumImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'album.png'))
68 artistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artist.png'))
69 artistsAlbumsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artistsalbums.png'))
70 favoritesImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'favorites.png'))
71 playlistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'playlist.png'))
72 usersplaylistsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'usersplaylists.png'))
73 popularSongsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongs.png'))
74 popularSongsArtistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongsArtist.png'))
75 songImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'song.png'))
76 defImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'default.tbn'))
77 fanImg
= xbmc
.translatePath(os
.path
.join(baseDir
, 'fanart.png'))
79 settings
= xbmcaddon
.Addon(id='plugin.audio.groove')
80 songsearchlimit
= int(settings
.getSetting('songsearchlimit'))
81 albumsearchlimit
= int(settings
.getSetting('albumsearchlimit'))
82 artistsearchlimit
= int(settings
.getSetting('artistsearchlimit'))
83 songspagelimit
= int(settings
.getSetting('songspagelimit'))
84 username
= settings
.getSetting('username')
85 password
= settings
.getSetting('password')
89 self
._handle
= int(sys
.argv
[1])
90 if os
.path
.isdir(cacheDir
) == False:
92 xbmc
.log("Made " + cacheDir
)
93 artDir
= xbmc
.translatePath(thumbDir
)
94 if os
.path
.isdir(artDir
) == False:
96 xbmc
.log("Made " + artDir
)
101 self
.userid
= self
._get
_login
()
104 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
106 self
._add
_dir
('Search for songs...', '', MODE_SEARCH_SONGS
, self
.songImg
, 0)
107 self
._add
_dir
('Search for albums...', '', MODE_SEARCH_ALBUMS
, self
.albumImg
, 0)
108 self
._add
_dir
('Search for artists...', '', MODE_SEARCH_ARTISTS
, self
.artistImg
, 0)
109 self
._add
_dir
(searchArtistsAlbumsName
, '', MODE_SEARCH_ARTISTS_ALBUMS
, self
.artistsAlbumsImg
, 0)
110 self
._add
_dir
("Search for user's playlists...", '', MODE_SEARCH_PLAYLISTS
, self
.usersplaylistsImg
, 0)
111 self
._add
_dir
('Popular songs for artist...', '', MODE_ARTIST_POPULAR
, self
.popularSongsArtistImg
, 0)
112 self
._add
_dir
('Popular songs', '', MODE_POPULAR_SONGS
, self
.popularSongsImg
, 0)
113 if (self
.userid
!= 0):
114 self
._add
_dir
('My favorites', '', MODE_FAVORITES
, self
.favoritesImg
, 0)
115 self
._add
_dir
('My playlists', '', MODE_PLAYLISTS
, self
.playlistImg
, 0)
118 def searchSongs(self
):
119 query
= self
._get
_keyboard
(default
="", heading
="Search for songs")
121 songs
= groovesharkApi
.getSongSearchResults(query
, limit
= self
.songsearchlimit
)
123 self
._add
_songs
_directory
(songs
)
125 dialog
= xbmcgui
.Dialog()
126 dialog
.ok('Grooveshark XBMC', 'No matching songs.')
132 def searchAlbums(self
):
133 query
= self
._get
_keyboard
(default
="", heading
="Search for albums")
135 albums
= groovesharkApi
.getAlbumSearchResults(query
, limit
= self
.albumsearchlimit
)
136 if (len(albums
) > 0):
137 self
._add
_albums
_directory
(albums
)
139 dialog
= xbmcgui
.Dialog()
140 dialog
.ok('Grooveshark XBMC', 'No matching albums.')
146 def searchArtists(self
):
147 query
= self
._get
_keyboard
(default
="", heading
="Search for artists")
149 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
150 if (len(artists
) > 0):
151 self
._add
_artists
_directory
(artists
)
153 dialog
= xbmcgui
.Dialog()
154 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
159 # Search for playlists
160 def searchPlaylists(self
):
161 query
= self
._get
_keyboard
(default
="", heading
="Username")
163 playlists
= groovesharkApi
.getUserPlaylistsEx(query
)
164 if (len(playlists
) > 0):
165 self
._add
_playlists
_directory
(playlists
)
167 dialog
= xbmcgui
.Dialog()
168 dialog
.ok('Grooveshark XBMC', 'No Grooveshark playlists found.')
173 # Search for artists albums
174 def searchArtistsAlbums(self
, artistName
= None):
175 if artistName
== None or artistName
== searchArtistsAlbumsName
:
176 query
= self
._get
_keyboard
(default
="", heading
="Search for artist's albums")
180 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
181 if (len(artists
) > 0):
184 xbmc
.log("Found " + artist
[0] + "...")
185 albums
= groovesharkApi
.getArtistAlbums(artistID
, limit
= self
.albumsearchlimit
)
186 if (len(albums
) > 0):
187 self
._add
_albums
_directory
(albums
)
189 dialog
= xbmcgui
.Dialog()
190 dialog
.ok('Grooveshark XBMC', 'No matching albums.')
193 dialog
= xbmcgui
.Dialog()
194 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
201 userid
= self
._get
_login
()
203 favorites
= groovesharkApi
.getUserFavoriteSongs()
204 if (len(favorites
) > 0):
205 self
._add
_songs
_directory
(favorites
)
207 dialog
= xbmcgui
.Dialog()
208 dialog
.ok('Grooveshark XBMC', 'You have no favorites.')
212 def popularSongs(self
):
213 popular
= groovesharkApi
.getPopularSongsToday(limit
= self
.songsearchlimit
)
214 if (len(popular
) > 0):
215 self
._add
_songs
_directory
(popular
)
217 dialog
= xbmcgui
.Dialog()
218 dialog
.ok('Grooveshark XBMC', 'No popular songs.')
223 userid
= self
._get
_login
()
225 playlists
= groovesharkApi
.getUserPlaylists()
226 if (len(playlists
) > 0):
227 self
._add
_playlists
_directory
(playlists
)
229 dialog
= xbmcgui
.Dialog()
230 dialog
.ok('Grooveshark XBMC', 'You have no Grooveshark playlists.')
233 dialog
= xbmcgui
.Dialog()
234 dialog
.ok('Grooveshark XBMC', 'You must be logged in ', ' to see your Grooveshark playlists.')
236 # Make songs a favorite
237 def favorite(self
, songid
):
238 userid
= self
._get
_login
()
240 xbmc
.log("Favorite song: " + str(songid
))
241 groovesharkApi
.addUserFavoriteSong(songID
= songid
)
242 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Added to favorites, 1000, ' + thumbDef
+ ')')
244 dialog
= xbmcgui
.Dialog()
245 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to add favorites.')
247 # Show selected album
248 def album(self
, albumid
):
249 album
= groovesharkApi
.getAlbumSongs(albumid
, limit
= self
.songsearchlimit
)
250 self
._add
_songs
_directory
(album
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
252 # Show selected artist
253 def artist(self
, artistid
):
254 albums
= groovesharkApi
.getArtistAlbums(artistid
, limit
= self
.albumsearchlimit
)
255 self
._add
_albums
_directory
(albums
)
257 # Show selected playlist
258 def playlist(self
, playlistid
):
259 userid
= self
._get
_login
()
261 songs
= groovesharkApi
.getPlaylistSongs(playlistid
)
262 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
264 dialog
= xbmcgui
.Dialog()
265 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to get Grooveshark playlists.')
267 # Show popular songs of the artist
268 def artistPopularSongs(self
):
269 query
= self
._get
_keyboard
(default
="", heading
="Artist")
271 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
272 if (len(artists
) > 0):
275 xbmc
.log("Found " + artist
[0] + "...")
276 songs
= groovesharkApi
.getArtistPopularSongs(artistID
, limit
= self
.songsearchlimit
)
278 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
280 dialog
= xbmcgui
.Dialog()
281 dialog
.ok('Grooveshark XBMC', 'No popular songs.')
284 dialog
= xbmcgui
.Dialog()
285 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
291 def playSong(self
, item
):
292 songid
= item
.getProperty('songid')
293 song
= groovesharkApi
.getSongURLFromSongID(songid
)
296 xbmc
.log("Playing: " + song
)
297 xbmcplugin
.setResolvedUrl(handle
=int(sys
.argv
[1]), succeeded
=True, listitem
=item
)
299 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Unable to play song, 1000, ' + thumbDef
+ ')')
301 # Make a song directory item
302 def songItem(self
, songid
, name
, album
, artist
, coverart
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
):
303 songImg
= self
._get
_icon
(coverart
, 'song-' + str(songid
) + "-image")
304 if trackLabelFormat
== NAME_ALBUM_ARTIST_LABEL
:
305 trackLabel
= name
+ " - " + album
+ " - " + artist
307 trackLabel
= artist
+ " - " + album
+ " - " + name
308 item
= xbmcgui
.ListItem(label
= trackLabel
, thumbnailImage
=songImg
, iconImage
=songImg
)
309 item
.setInfo( type="music", infoLabels
={ "title": name
, "album": album
, "artist": artist
} )
310 item
.setProperty('mimetype', 'audio/mpeg')
311 item
.setProperty("IsPlayable", "true")
312 item
.setProperty('songid', str(songid
))
313 item
.setProperty('coverart', songImg
)
314 item
.setProperty('title', name
)
315 item
.setProperty('album', album
)
316 item
.setProperty('artist', artist
)
321 def songPage(self
, page
, trackLabelFormat
):
322 self
._add
_songs
_directory
([], trackLabelFormat
, page
)
325 def _get_keyboard(self
, default
="", heading
="", hidden
=False):
326 kb
= xbmc
.Keyboard(default
, heading
, hidden
)
328 if (kb
.isConfirmed()):
329 return unicode(kb
.getText(), "utf-8")
332 # Login to grooveshark
333 def _get_login(self
):
334 if (self
.username
== "" or self
.password
== ""):
335 dialog
= xbmcgui
.Dialog()
336 dialog
.ok('Grooveshark XBMC', 'Unable to login.', 'Check username and password in settings.')
340 uid
= groovesharkApi
.login(self
.username
, self
.password
)
344 dialog
= xbmcgui
.Dialog()
345 dialog
.ok('Grooveshark XBMC', 'Unable to login.', 'Check username and password in settings.')
348 # Get a song directory item
349 def _get_song_item(self
, song
, trackLabelFormat
):
355 return self
.songItem(songid
, name
, album
, artist
, coverart
, trackLabelFormat
)
358 def _get_icon(self
, url
, songid
):
360 localThumb
= os
.path
.join(xbmc
.translatePath(os
.path
.join(thumbDir
, str(songid
)))) + '.tbn'
362 if os
.path
.isfile(localThumb
) == False:
363 loc
= urllib
.URLopener()
364 loc
.retrieve(url
, localThumb
)
366 shutil
.copy2(thumbDef
, localThumb
)
367 return os
.path
.join(os
.path
.join(thumbDir
, str(songid
))) + '.tbn'
371 # Add songs to directory
372 def _add_songs_directory(self
, songs
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
, page
=0):
374 totalSongs
= len(songs
)
378 if page
== 0 and totalSongs
<= self
.songspagelimit
:
379 xbmc
.log("Found " + str(totalSongs
) + " songs...")
384 self
._setSavedSongs
(songs
)
386 songs
= self
._getSavedSongs
()
387 totalSongs
= len(songs
)
390 start
= page
* self
.songspagelimit
391 end
= start
+ self
.songspagelimit
392 songs
= songs
[start
:end
]
395 item
= self
._get
_song
_item
(song
, trackLabelFormat
)
396 coverart
= item
.getProperty('coverart')
401 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
) \
402 +"&album="+urllib
.quote_plus(songalbum
) \
403 +"&artist="+urllib
.quote_plus(songartist
) \
404 +"&coverart="+urllib
.quote_plus(coverart
)
405 fav
=sys
.argv
[0]+"?mode="+str(MODE_FAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)
407 menuItems
.append(("Grooveshark favorite", "XBMC.RunPlugin("+fav
+")"))
408 item
.addContextMenuItems(menuItems
, replaceItems
=False)
409 xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=item
,isFolder
=False, totalItems
=len(songs
))
412 if totalSongs
> page
* self
.songspagelimit
:
413 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG_PAGE
)+"&id=0"+"&page="+str(page
)+"&label="+str(trackLabelFormat
)
414 self
._add
_dir
('More songs...', u
, MODE_SONG_PAGE
, self
.songImg
, 0, totalSongs
- (page
* self
.songspagelimit
))
416 xbmcplugin
.setContent(self
._handle
, 'songs')
417 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
419 # Add albums to directory
420 def _add_albums_directory(self
, albums
):
422 xbmc
.log("Found " + str(n
) + " albums...")
426 albumArtistName
= album
[0]
429 albumImage
= self
._get
_icon
(album
[4], 'album-' + str(albumID
))
430 self
._add
_dir
(albumName
+ " - " + albumArtistName
, '', MODE_ALBUM
, albumImage
, albumID
, n
)
432 xbmcplugin
.setContent(self
._handle
, 'albums')
433 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ALBUM_IGNORE_THE
)
434 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
436 # Add artists to directory
437 def _add_artists_directory(self
, artists
):
439 xbmc
.log("Found " + str(n
) + " artists...")
443 artistName
= artist
[0]
445 self
._add
_dir
(artistName
, '', MODE_ARTIST
, self
.artistImg
, artistID
, n
)
447 xbmcplugin
.setContent(self
._handle
, 'artists')
448 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ARTIST_IGNORE_THE
)
449 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
451 # Add playlists to directory
452 def _add_playlists_directory(self
, playlists
):
454 xbmc
.log("Found " + str(n
) + " playlists...")
457 playlist
= playlists
[i
]
458 playlistName
= playlist
[0]
459 playlistID
= playlist
[1]
460 dir = self
._add
_dir
(playlistName
, '', MODE_PLAYLIST
, self
.playlistImg
, playlistID
, n
)
462 xbmcplugin
.setContent(self
._handle
, 'files')
463 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_LABEL
)
464 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
466 # Add whatever directory
467 def _add_dir(self
, name
, url
, mode
, iconimage
, id, items
=1):
469 u
=sys
.argv
[0]+"?mode="+str(mode
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
472 dir=xbmcgui
.ListItem(name
, iconImage
=iconimage
, thumbnailImage
=iconimage
)
473 dir.setInfo( type="Music", infoLabels
={ "title": name
} )
474 return xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=dir,isFolder
=True, totalItems
=items
)
476 def _getSavedSongs(self
):
477 path
= os
.path
.join(cacheDir
, 'songs.dmp')
480 songs
= pickle
.load(f
)
487 def _setSavedSongs(self
, songs
):
489 # Create the 'data' directory if it doesn't exist.
490 if not os
.path
.exists(cacheDir
):
491 os
.makedirs(cacheDir
)
492 path
= os
.path
.join(cacheDir
, 'songs.dmp')
494 pickle
.dump(songs
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
497 xbmc
.log("An error occurred saving songs")
502 # Parse URL parameters
505 paramstring
=sys
.argv
[2]
506 xbmc
.log(paramstring
)
507 if len(paramstring
)>=2:
509 cleanedparams
=params
.replace('?','')
510 if (params
[len(params
)-1]=='/'):
511 params
=params
[0:len(params
)-2]
512 pairsofparams
=cleanedparams
.split('&')
514 for i
in range(len(pairsofparams
)):
516 splitparams
=pairsofparams
[i
].split('=')
517 if (len(splitparams
))==2:
518 param
[splitparams
[0]]=splitparams
[1]
522 grooveshark
= Groveshark();
526 try: mode
=int(params
["mode"])
529 try: id=int(params
["id"])
532 # Call function for URL
534 grooveshark
.categories()
536 elif mode
==MODE_SEARCH_SONGS
:
537 grooveshark
.searchSongs()
539 elif mode
==MODE_SEARCH_ALBUMS
:
540 grooveshark
.searchAlbums()
542 elif mode
==MODE_SEARCH_ARTISTS
:
543 grooveshark
.searchArtists()
545 elif mode
==MODE_SEARCH_ARTISTS_ALBUMS
:
546 try: name
=urllib
.unquote_plus(params
["name"])
550 grooveshark
.searchArtistsAlbums(name
)
552 elif mode
==MODE_SEARCH_PLAYLISTS
:
553 grooveshark
.searchPlaylists()
555 elif mode
==MODE_POPULAR_SONGS
:
556 grooveshark
.popularSongs()
558 elif mode
==MODE_ARTIST_POPULAR
:
559 grooveshark
.artistPopularSongs()
561 elif mode
==MODE_FAVORITES
:
562 grooveshark
.favorites()
564 elif mode
==MODE_PLAYLISTS
:
565 grooveshark
.playlists()
567 elif mode
==MODE_SONG_PAGE
:
568 try: page
=urllib
.unquote_plus(params
["page"])
570 try: label
=urllib
.unquote_plus(params
["label"])
572 grooveshark
.songPage(page
, label
)
574 elif mode
==MODE_SONG
:
575 try: name
=urllib
.unquote_plus(params
["name"])
577 try: album
=urllib
.unquote_plus(params
["album"])
579 try: artist
=urllib
.unquote_plus(params
["artist"])
581 try: coverart
=urllib
.unquote_plus(params
["coverart"])
583 song
= grooveshark
.songItem(id, name
, album
, artist
, coverart
)
584 grooveshark
.playSong(song
)
586 elif mode
==MODE_ARTIST
:
587 grooveshark
.artist(id)
589 elif mode
==MODE_ALBUM
:
590 grooveshark
.album(id)
592 elif mode
==MODE_PLAYLIST
:
593 grooveshark
.playlist(id)
595 elif mode
==MODE_FAVORITE
:
596 grooveshark
.favorite(id)
599 xbmcplugin
.endOfDirectory(int(sys
.argv
[1]))