1 import urllib
, urllib2
, re
, xbmcplugin
, xbmcgui
, xbmc
, sys
, os
, time
, pprint
, shutil
, xbmcaddon
5 MODE_SEARCH_ARTISTS
= 3
12 MODE_SIMILAR_ARTISTS
= 10
20 resDir
= xbmc
.translatePath(os
.path
.join(baseDir
, 'resources'))
21 libDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'lib'))
22 imgDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'img'))
23 thumbDir
= os
.path
.join('special://masterprofile/addon_data/', os
.path
.join(os
.path
.basename(os
.getcwd()), 'thumb'))
24 favoritesCache
= xbmc
.translatePath(os
.path
.join('special://masterprofile/addon_data/', os
.path
.join(os
.path
.basename(os
.getcwd()), 'favorites.dmp')))
26 sys
.path
.append (libDir
)
27 from GrooveAPI
import *
28 groovesharkApi
= GrooveAPI()
31 def __init__( self
, *args
, **kwargs
):
32 self
.__dict
__.update( kwargs
)
36 albumImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'album.png'))
37 artistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artist.png'))
38 favoritesImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'favorites.png'))
39 playlistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'playlist.png'))
40 popularImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popular.png'))
41 songImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'song.png'))
42 defImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'default.tbn'))
43 fanImg
= xbmc
.translatePath(os
.path
.join(baseDir
, 'fanart.png'))
45 settings
= xbmcaddon
.Addon(id='plugin.audio.groove')
46 songsearchlimit
= settings
.getSetting('songsearchlimit')
47 albumsearchlimit
= settings
.getSetting('albumsearchlimit')
48 artistsearchlimit
= settings
.getSetting('artistsearchlimit')
49 username
= settings
.getSetting('username')
50 password
= settings
.getSetting('password')
53 self
._handle
= int(sys
.argv
[1])
57 xbmc
.log(self
.username
+ ", limits: " + str(self
.songsearchlimit
) + ", " + str(self
.albumsearchlimit
) + ", " + str(self
.artistsearchlimit
))
59 userid
= self
._get
_login
()
62 groovesharkApi
.setRemoveDuplicates(True)
63 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
64 if os
.path
.isdir(thumbDir
) == False:
67 self
._add
_dir
('Search songs', '', MODE_SEARCH_SONGS
, self
.songImg
, 0)
68 self
._add
_dir
('Search albums', '', MODE_SEARCH_ALBUMS
, self
.albumImg
, 0)
69 self
._add
_dir
('Search artists', '', MODE_SEARCH_ARTISTS
, self
.artistImg
, 0)
70 self
._add
_dir
('Popular', '', MODE_POPULAR
, self
.popularImg
, 0)
72 self
._add
_dir
('Favorites', '', MODE_FAVORITES
, self
.favoritesImg
, 0)
73 self
._add
_dir
('Playlists', '', MODE_PLAYLISTS
, self
.playlistImg
, 0)
75 def searchSongs(self
):
76 query
= self
._get
_keyboard
(default
="", heading
="Search songs")
78 songs
= groovesharkApi
.searchSongs(query
, limit
= self
.songsearchlimit
)
80 self
._add
_songs
_directory
(songs
)
82 dialog
= xbmcgui
.Dialog()
83 dialog
.ok('Grooveshark', 'No matching songs.')
86 def searchAlbums(self
):
87 query
= self
._get
_keyboard
(default
="", heading
="Search albums")
89 albums
= groovesharkApi
.searchAlbums(query
, limit
= self
.albumsearchlimit
)
91 self
._add
_albums
_directory
(albums
)
93 dialog
= xbmcgui
.Dialog()
94 dialog
.ok('Grooveshark', 'No matching albums.')
97 def searchArtists(self
):
98 query
= self
._get
_keyboard
(default
="", heading
="Search artists")
100 artists
= groovesharkApi
.searchArtists(query
, limit
= self
.artistsearchlimit
)
101 if (len(artists
) > 0):
102 self
._add
_artists
_directory
(artists
)
104 dialog
= xbmcgui
.Dialog()
105 dialog
.ok('Grooveshark', 'No matching artists.')
109 favorites
= self
._get
_favorites
()
110 if (len(favorites
) > 0):
111 self
._add
_songs
_directory
(favorites
)
113 dialog
= xbmcgui
.Dialog()
114 dialog
.ok('Grooveshark', 'You have no favorites.')
118 popular
= groovesharkApi
.popularGetSongs(limit
= self
.songsearchlimit
)
119 if (len(popular
) > 0):
120 self
._add
_songs
_directory
(popular
)
122 dialog
= xbmcgui
.Dialog()
123 dialog
.ok('Grooveshark', 'No popular songs.')
127 userid
= self
._get
_login
()
129 playlists
= groovesharkApi
.userGetPlaylists()
130 if (len(playlists
) > 0):
131 self
._add
_playlists
_directory
(playlists
)
133 dialog
= xbmcgui
.Dialog()
134 dialog
.ok('Grooveshark', 'You have no playlists.')
137 def favorite(self
, songid
):
138 userid
= self
._get
_login
()
140 xbmc
.log("Favorite song: " + str(songid
))
141 groovesharkApi
.favoriteSong(songID
= songid
)
142 os
.remove(favoritesCache
)
144 dialog
= xbmcgui
.Dialog()
145 dialog
.ok('Grooveshark', 'You must be logged in', 'to add favorites.')
147 def unfavorite(self
, songid
):
148 userid
= self
._get
_login
()
150 xbmc
.log("Unfavorite song: " + str(songid
))
151 groovesharkApi
.unfavoriteSong(songID
= songid
)
152 os
.remove(favoritesCache
)
154 dialog
= xbmcgui
.Dialog()
155 dialog
.ok('Grooveshark', 'You must be logged in', 'to remove favorites.')
157 def frown(self
, songid
):
158 userid
= self
._get
_login
()
160 xbmc
.log("Frown song: " + str(songid
))
161 if groovesharkApi
.radioFrown(songId
= songid
) != True:
162 xbmc
.log("Unable to frown song " + str(songid
))
164 dialog
= xbmcgui
.Dialog()
165 dialog
.ok('Grooveshark', 'You must be logged in', 'to frown a song.')
167 def similarArtists(self
, artistId
):
168 similar
= groovesharkApi
.artistGetSimilar(artistId
, limit
= self
.artistsearchlimit
)
169 if (len(similar
) > 0):
170 self
._add
_artists
_directory
(similar
)
172 dialog
= xbmcgui
.Dialog()
173 dialog
.ok('Grooveshark', 'No similar artists.')
176 def album(self
,albumid
):
177 album
= groovesharkApi
.albumGetSongs(albumId
= albumid
, limit
= self
.songsearchlimit
)
178 self
._add
_songs
_directory
(album
)
180 def artist(self
, artistid
):
181 albums
= groovesharkApi
.artistGetAlbums(artistId
= artistid
, limit
= self
.albumsearchlimit
)
182 self
._add
_albums
_directory
(albums
, artistid
)
184 def playlist(self
, playlistid
):
185 userid
= self
._get
_login
()
187 songs
= groovesharkApi
.playlistGetSongs(playlistId
= playlistid
, limit
= self
.songsearchlimit
)
188 self
._add
_songs
_directory
(songs
)
190 dialog
= xbmcgui
.Dialog()
191 dialog
.ok('Grooveshark', 'You must be logged in', 'to get playlists.')
193 def playSong(self
, item
):
194 url
= item
.getProperty('url')
195 xbmc
.log("Playing: " + url
)
196 xbmcplugin
.setResolvedUrl(handle
=int(sys
.argv
[1]), succeeded
=True, listitem
=item
)
198 def songItem(self
, id, name
, album
, artist
, duration
, thumb
, image
):
199 url
= groovesharkApi
.getStreamURL(id)
200 # Only try to get the image
202 songImg
= self
._get
_icon
(image
, 'song-' + str(id) + "-image")
205 songThm
= self
._get
_icon
(thumb
, 'song-' + str(id) + "-thumb")
207 item
= xbmcgui
.ListItem(label
= artist
+ " - " + album
+ " - " + name
, path
=url
, thumbnailImage
=songThm
, iconImage
=songImg
)
208 item
.setInfo( type="music", infoLabels
={ "title": name
, "duration": duration
, "album": album
, "artist": artist
} )
209 item
.setProperty('mimetype', 'audio/mpeg')
210 item
.setProperty("IsPlayable", "true")
211 item
.setProperty('url', url
)
212 item
.setProperty('thumb', songThm
)
213 item
.setProperty('image', songImg
)
217 def _get_favorites(self
):
219 # if the cache does not exist or is older than x hours then reload
220 if (os
.path
.isfile(favoritesCache
) == False) or (time
.time() - os
.path
.getmtime(favoritesCache
) > 3*60*60):
221 xbmc
.log("Refresh favorites cache")
222 userid
= self
._get
_login
()
224 favorites
= groovesharkApi
.userGetFavoriteSongs(userid
)
225 f
= open(favoritesCache
, 'wb')
226 pickle
.dump(favorites
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
228 xbmc
.log("Refreshed favorites cache")
229 # if not old then read from cache
230 elif os
.path
.isfile(favoritesCache
):
231 xbmc
.log("Existing favorites cache")
232 f
= open(favoritesCache
, 'rb')
233 favorites
= pickle
.load(f
)
238 def _get_keyboard(self
, default
="", heading
="", hidden
=False):
239 kb
= xbmc
.Keyboard(default
, heading
, hidden
)
241 if (kb
.isConfirmed()):
242 return unicode(kb
.getText(), "utf-8")
245 def _get_login(self
):
246 if (self
.username
== "" or self
.password
== ""):
247 dialog
= xbmcgui
.Dialog()
248 dialog
.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
251 if groovesharkApi
.loggedInStatus() == 1:
252 groovesharkApi
.logout()
253 userid
= groovesharkApi
.loginExt(self
.username
, self
.password
)
255 xbmc
.log("Logged in")
258 dialog
= xbmcgui
.Dialog()
259 dialog
.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
262 def _get_song_item(self
, song
):
270 return self
.songItem(id, name
, album
, artist
, duration
, thumb
, image
)
273 def _get_icon(self
, url
, id):
274 localThumb
= os
.path
.join(xbmc
.translatePath(os
.path
.join(thumbDir
, str(id)))) + '.tbn'
276 if os
.path
.isfile(localThumb
) == False:
277 xbmc
.log('Downloading ' + url
+ ' to ' + localThumb
)
278 loc
= urllib
.URLopener()
279 loc
.retrieve(url
, localThumb
)
281 xbmc
.log('URL download failed of ' + url
+ ' to ' + localThumb
)
284 return os
.path
.join(os
.path
.join(thumbDir
, str(id))) + '.tbn'
286 def _add_songs_directory(self
, songs
):
288 xbmc
.log("Found " + str(n
) + " songs...")
292 item
= self
._get
_song
_item
(song
)
293 songurl
= item
.getProperty('url')
294 songthumb
= item
.getProperty('thumb')
295 songimage
= item
.getProperty('image')
298 songduration
= song
[2]
301 u
=sys
.argv
[0]+"?url="+urllib
.quote_plus(songurl
) \
302 +"&mode="+str(MODE_SONG
)+"&name="+urllib
.quote_plus(songname
)+"&id=" \
304 +"&album="+urllib
.quote_plus(songalbum
) \
305 +"&artist="+urllib
.quote_plus(songartist
) \
306 +"&duration="+str(songduration
) \
307 +"&thumb="+urllib
.quote_plus(songthumb
) \
308 +"&image="+urllib
.quote_plus(songimage
)
309 fav
=sys
.argv
[0]+"?url="+urllib
.quote_plus(songurl
)+"&mode="+str(MODE_FAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)
310 unfav
=sys
.argv
[0]+"?url="+urllib
.quote_plus(songurl
)+"&mode="+str(MODE_UNFAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)
312 menuItems
.append(("Grooveshark Favorite", "XBMC.RunPlugin("+fav
+")"))
313 menuItems
.append(("Not Grooveshark Favorite", "XBMC.RunPlugin("+unfav
+")"))
314 item
.addContextMenuItems(menuItems
, replaceItems
=False)
315 xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=item
,isFolder
=False,totalItems
=n
)
317 xbmcplugin
.setContent(self
._handle
, 'songs')
318 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
320 def _add_albums_directory(self
, albums
, artistid
=0):
322 xbmc
.log("Found " + str(n
) + " albums...")
326 albumArtistName
= album
[0]
329 albumImage
= self
._get
_icon
(album
[4], 'album-' + str(albumID
))
330 self
._add
_dir
(albumName
+ " - " + albumArtistName
, '', MODE_ALBUM
, albumImage
, albumID
, n
)
333 self
._add
_dir
('Similar artists...', '', MODE_SIMILAR_ARTISTS
, self
.artistImg
, artistid
)
334 xbmcplugin
.setContent(self
._handle
, 'albums')
335 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ALBUM_IGNORE_THE
)
336 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
338 def _add_artists_directory(self
, artists
):
340 xbmc
.log("Found " + str(n
) + " artists...")
344 artistName
= artist
[0]
346 self
._add
_dir
(artistName
, '', MODE_ARTIST
, self
.artistImg
, artistID
, n
)
348 xbmcplugin
.setContent(self
._handle
, 'artists')
349 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ARTIST_IGNORE_THE
)
350 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
352 def _add_playlists_directory(self
, playlists
):
354 xbmc
.log("Found " + str(n
) + " playlists...")
357 playlist
= playlists
[i
]
358 playlistName
= playlist
[0]
359 playlistID
= playlist
[1]
360 self
._add
_dir
(playlistName
, '', MODE_PLAYLIST
, self
.playlistImg
, playlistID
, n
)
362 xbmcplugin
.setContent(self
._handle
, 'files')
363 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_PLAYLIST_ORDER
)
364 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
366 def _add_dir(self
, name
, url
, mode
, iconimage
, id, items
=1):
367 u
=sys
.argv
[0]+"?url="+urllib
.quote_plus(url
)+"&mode="+str(mode
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
368 dir=xbmcgui
.ListItem(name
, iconImage
=iconimage
, thumbnailImage
=iconimage
)
369 dir.setInfo( type="Music", infoLabels
={ "title": name
} )
370 # Codes from http://xbmc-scripting.googlecode.com/svn/trunk/Script%20Templates/common/gui/codes.py
372 menuItems
.append(("Select", "XBMC.executebuiltin(Action(7))"))
373 dir.addContextMenuItems(menuItems
, replaceItems
=True)
374 return xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=dir,isFolder
=True, totalItems
=items
)
379 paramstring
=sys
.argv
[2]
380 if len(paramstring
)>=2:
382 cleanedparams
=params
.replace('?','')
383 if (params
[len(params
)-1]=='/'):
384 params
=params
[0:len(params
)-2]
385 pairsofparams
=cleanedparams
.split('&')
387 for i
in range(len(pairsofparams
)):
389 splitparams
=pairsofparams
[i
].split('=')
390 if (len(splitparams
))==2:
391 param
[splitparams
[0]]=splitparams
[1]
395 grooveshark
= Groveshark();
403 try: url
=urllib
.unquote_plus(params
["url"])
405 try: name
=urllib
.unquote_plus(params
["name"])
407 try: mode
=int(params
["mode"])
409 try: id=int(params
["id"])
416 grooveshark
.categories()
418 elif mode
==MODE_SEARCH_SONGS
:
419 grooveshark
.searchSongs()
421 elif mode
==MODE_SEARCH_ALBUMS
:
422 grooveshark
.searchAlbums()
424 elif mode
==MODE_SEARCH_ARTISTS
:
425 grooveshark
.searchArtists()
427 elif mode
==MODE_POPULAR
:
428 grooveshark
.popular()
430 elif mode
==MODE_PLAYLISTS
:
431 grooveshark
.playlists()
433 elif mode
==MODE_FAVORITES
:
434 grooveshark
.favorites()
436 elif mode
==MODE_SONG
:
437 try: name
=urllib
.unquote_plus(params
["name"])
439 try: album
=urllib
.unquote_plus(params
["album"])
441 try: artist
=urllib
.unquote_plus(params
["artist"])
443 try: duration
=int(params
["duration"])
445 try: thumb
=urllib
.unquote_plus(params
["thumb"])
447 try: image
=urllib
.unquote_plus(params
["image"])
449 song
= grooveshark
.songItem(id, name
, album
, artist
, duration
, thumb
, image
)
450 grooveshark
.playSong(song
)
452 elif mode
==MODE_ARTIST
:
453 grooveshark
.artist(lastID
)
455 elif mode
==MODE_ALBUM
:
456 grooveshark
.album(lastID
)
458 elif mode
==MODE_PLAYLIST
:
459 grooveshark
.playlist(lastID
)
461 elif mode
==MODE_FAVORITE
:
462 grooveshark
.favorite(lastID
)
464 elif mode
==MODE_UNFAVORITE
:
465 grooveshark
.unfavorite(lastID
)
467 elif mode
==MODE_SIMILAR_ARTISTS
:
468 grooveshark
.similarArtists(lastID
)
470 if (mode
< MODE_SONG
):
471 xbmcplugin
.endOfDirectory(int(sys
.argv
[1]))