0e0261e90ed6035a95d8c4faee6ed63492e5c1e2
[clinton/xbmc-groove.git] / default.py
1 import urllib, urllib2, re, xbmcplugin, xbmcgui, xbmc, sys, os, time, pprint, shutil, xbmcaddon
2
3 MODE_SEARCH_SONGS = 1
4 MODE_SEARCH_ALBUMS = 2
5 MODE_SEARCH_ARTISTS = 3
6 MODE_POPULAR = 4
7 MODE_FAVORITES = 5
8 MODE_PLAYLISTS = 6
9 MODE_ALBUM = 7
10 MODE_ARTIST = 8
11 MODE_PLAYLIST = 9
12 MODE_SIMILAR_ARTISTS = 10
13 MODE_SONG = 11
14 MODE_FAVORITE = 12
15 MODE_UNFAVORITE = 13
16
17 lastID = 0
18
19 baseDir = os.getcwd()
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')))
25
26 sys.path.append (libDir)
27 from GrooveAPI import *
28 groovesharkApi = GrooveAPI()
29
30 class _Info:
31 def __init__( self, *args, **kwargs ):
32 self.__dict__.update( kwargs )
33
34 class Groveshark:
35
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'))
44
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')
51
52 def __init__( self ):
53 self._handle = int(sys.argv[1])
54
55 def categories(self):
56
57 xbmc.log(self.username + ", limits: " + str(self.songsearchlimit) + ", " + str(self.albumsearchlimit) + ", " + str(self.artistsearchlimit))
58
59 userid = self._get_login()
60
61 # Setup
62 groovesharkApi.setRemoveDuplicates(True)
63 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
64 if os.path.isdir(thumbDir) == False:
65 os.makedirs(thumbDir)
66
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)
71 if (userid != 0):
72 self._add_dir('Favorites', '', MODE_FAVORITES, self.favoritesImg, 0)
73 self._add_dir('Playlists', '', MODE_PLAYLISTS, self.playlistImg, 0)
74
75 def searchSongs(self):
76 query = self._get_keyboard(default="", heading="Search songs")
77 if (query):
78 songs = groovesharkApi.searchSongs(query, limit = self.songsearchlimit)
79 if (len(songs) > 0):
80 self._add_songs_directory(songs)
81 else:
82 dialog = xbmcgui.Dialog()
83 dialog.ok('Grooveshark', 'No matching songs.')
84 self.categories()
85
86 def searchAlbums(self):
87 query = self._get_keyboard(default="", heading="Search albums")
88 if (query):
89 albums = groovesharkApi.searchAlbums(query, limit = self.albumsearchlimit)
90 if (len(albums) > 0):
91 self._add_albums_directory(albums)
92 else:
93 dialog = xbmcgui.Dialog()
94 dialog.ok('Grooveshark', 'No matching albums.')
95 self.categories()
96
97 def searchArtists(self):
98 query = self._get_keyboard(default="", heading="Search artists")
99 if (query):
100 artists = groovesharkApi.searchArtists(query, limit = self.artistsearchlimit)
101 if (len(artists) > 0):
102 self._add_artists_directory(artists)
103 else:
104 dialog = xbmcgui.Dialog()
105 dialog.ok('Grooveshark', 'No matching artists.')
106 self.categories()
107
108 def favorites(self):
109 favorites = self._get_favorites()
110 if (len(favorites) > 0):
111 self._add_songs_directory(favorites)
112 else:
113 dialog = xbmcgui.Dialog()
114 dialog.ok('Grooveshark', 'You have no favorites.')
115 self.categories()
116
117 def popular(self):
118 popular = groovesharkApi.popularGetSongs(limit = self.songsearchlimit)
119 if (len(popular) > 0):
120 self._add_songs_directory(popular)
121 else:
122 dialog = xbmcgui.Dialog()
123 dialog.ok('Grooveshark', 'No popular songs.')
124 self.categories()
125
126 def playlists(self):
127 userid = self._get_login()
128 if (userid != 0):
129 playlists = groovesharkApi.userGetPlaylists()
130 if (len(playlists) > 0):
131 self._add_playlists_directory(playlists)
132 else:
133 dialog = xbmcgui.Dialog()
134 dialog.ok('Grooveshark', 'You have no playlists.')
135 self.categories()
136
137 def favorite(self, songid):
138 userid = self._get_login()
139 if (userid != 0):
140 xbmc.log("Favorite song: " + str(songid))
141 groovesharkApi.favoriteSong(songID = songid)
142 os.remove(favoritesCache)
143 else:
144 dialog = xbmcgui.Dialog()
145 dialog.ok('Grooveshark', 'You must be logged in', 'to add favorites.')
146
147 def unfavorite(self, songid):
148 userid = self._get_login()
149 if (userid != 0):
150 xbmc.log("Unfavorite song: " + str(songid))
151 groovesharkApi.unfavoriteSong(songID = songid)
152 os.remove(favoritesCache)
153 else:
154 dialog = xbmcgui.Dialog()
155 dialog.ok('Grooveshark', 'You must be logged in', 'to remove favorites.')
156
157 def frown(self, songid):
158 userid = self._get_login()
159 if (userid != 0):
160 xbmc.log("Frown song: " + str(songid))
161 if groovesharkApi.radioFrown(songId = songid) != True:
162 xbmc.log("Unable to frown song " + str(songid))
163 else:
164 dialog = xbmcgui.Dialog()
165 dialog.ok('Grooveshark', 'You must be logged in', 'to frown a song.')
166
167 def similarArtists(self, artistId):
168 similar = groovesharkApi.artistGetSimilar(artistId, limit = self.artistsearchlimit)
169 if (len(similar) > 0):
170 self._add_artists_directory(similar)
171 else:
172 dialog = xbmcgui.Dialog()
173 dialog.ok('Grooveshark', 'No similar artists.')
174 self.categories()
175
176 def album(self,albumid):
177 album = groovesharkApi.albumGetSongs(albumId = albumid, limit = self.songsearchlimit)
178 self._add_songs_directory(album)
179
180 def artist(self, artistid):
181 albums = groovesharkApi.artistGetAlbums(artistId = artistid, limit = self.albumsearchlimit)
182 self._add_albums_directory(albums, artistid)
183
184 def playlist(self, playlistid):
185 userid = self._get_login()
186 if (userid != 0):
187 songs = groovesharkApi.playlistGetSongs(playlistId = playlistid, limit = self.songsearchlimit)
188 self._add_songs_directory(songs)
189 else:
190 dialog = xbmcgui.Dialog()
191 dialog.ok('Grooveshark', 'You must be logged in', 'to get playlists.')
192
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)
197
198 def songItem(self, id, name, album, artist, duration, thumb, image):
199 url = groovesharkApi.getStreamURL(id)
200 # Only try to get the image
201 if image != "":
202 songImg = self._get_icon(image, 'song-' + str(id) + "-image")
203 songThm = songImg
204 else:
205 songThm = self._get_icon(thumb, 'song-' + str(id) + "-thumb")
206 songImg = songThm
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)
214
215 return item
216
217 def _get_favorites(self):
218 favorites = []
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()
223 if (userid != 0):
224 favorites = groovesharkApi.userGetFavoriteSongs(userid)
225 f = open(favoritesCache, 'wb')
226 pickle.dump(favorites, f, protocol=pickle.HIGHEST_PROTOCOL)
227 f.close()
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)
234 f.close()
235
236 return favorites
237
238 def _get_keyboard(self, default="", heading="", hidden=False):
239 kb = xbmc.Keyboard(default, heading, hidden)
240 kb.doModal()
241 if (kb.isConfirmed()):
242 return unicode(kb.getText(), "utf-8")
243 return ''
244
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.')
249 return 0
250 else:
251 if groovesharkApi.loggedInStatus() == 1:
252 groovesharkApi.logout()
253 userid = groovesharkApi.loginExt(self.username, self.password)
254 if (userid != 0):
255 xbmc.log("Logged in")
256 return userid
257 else:
258 dialog = xbmcgui.Dialog()
259 dialog.ok('Grooveshark', 'Unable to login.', 'Check username and password in settings.')
260 return 0
261
262 def _get_song_item(self, song):
263 name = song[0]
264 id = song[1]
265 duration = song[2]
266 album = song[3]
267 artist = song[6]
268 thumb = song[8]
269 image = song[9]
270 return self.songItem(id, name, album, artist, duration, thumb, image)
271
272 # File download
273 def _get_icon(self, url, id):
274 localThumb = os.path.join(xbmc.translatePath(os.path.join(thumbDir, str(id)))) + '.tbn'
275 try:
276 if os.path.isfile(localThumb) == False:
277 xbmc.log('Downloading ' + url + ' to ' + localThumb)
278 loc = urllib.URLopener()
279 loc.retrieve(url, localThumb)
280 except:
281 xbmc.log('URL download failed of ' + url + ' to ' + localThumb)
282 return(self.defImg)
283
284 return os.path.join(os.path.join(thumbDir, str(id))) + '.tbn'
285
286 def _add_songs_directory(self, songs):
287 n = len(songs)
288 xbmc.log("Found " + str(n) + " songs...")
289 i = 0
290 while i < n:
291 song = songs[i]
292 item = self._get_song_item(song)
293 songurl = item.getProperty('url')
294 songthumb = item.getProperty('thumb')
295 songimage = item.getProperty('image')
296 songname = song[0]
297 songid = song[1]
298 songduration = song[2]
299 songalbum = song[3]
300 songartist = song[6]
301 u=sys.argv[0]+"?url="+urllib.quote_plus(songurl) \
302 +"&mode="+str(MODE_SONG)+"&name="+urllib.quote_plus(songname)+"&id=" \
303 +str(songid) \
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)
311 menuItems = []
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)
316 i = i + 1
317 xbmcplugin.setContent(self._handle, 'songs')
318 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
319
320 def _add_albums_directory(self, albums, artistid=0):
321 n = len(albums)
322 xbmc.log("Found " + str(n) + " albums...")
323 i = 0
324 while i < n:
325 album = albums[i]
326 albumArtistName = album[0]
327 albumName = album[2]
328 albumID = album[3]
329 albumImage = self._get_icon(album[4], 'album-' + str(albumID))
330 self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID, n)
331 i = i + 1
332 if artistid > 0:
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)
337
338 def _add_artists_directory(self, artists):
339 n = len(artists)
340 xbmc.log("Found " + str(n) + " artists...")
341 i = 0
342 while i < n:
343 artist = artists[i]
344 artistName = artist[0]
345 artistID = artist[1]
346 self._add_dir(artistName, '', MODE_ARTIST, self.artistImg, artistID, n)
347 i = i + 1
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)
351
352 def _add_playlists_directory(self, playlists):
353 n = len(playlists)
354 xbmc.log("Found " + str(n) + " playlists...")
355 i = 0
356 while i < n:
357 playlist = playlists[i]
358 playlistName = playlist[0]
359 playlistID = playlist[1]
360 self._add_dir(playlistName, '', MODE_PLAYLIST, self.playlistImg, playlistID, n)
361 i = i + 1
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)
365
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
371 menuItems = []
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)
375
376
377 def get_params():
378 param=[]
379 paramstring=sys.argv[2]
380 if len(paramstring)>=2:
381 params=sys.argv[2]
382 cleanedparams=params.replace('?','')
383 if (params[len(params)-1]=='/'):
384 params=params[0:len(params)-2]
385 pairsofparams=cleanedparams.split('&')
386 param={}
387 for i in range(len(pairsofparams)):
388 splitparams={}
389 splitparams=pairsofparams[i].split('=')
390 if (len(splitparams))==2:
391 param[splitparams[0]]=splitparams[1]
392 print param
393 return param
394
395 grooveshark = Groveshark();
396
397 params=get_params()
398 url=None
399 name=None
400 mode=None
401 id=None
402
403 try: url=urllib.unquote_plus(params["url"])
404 except: pass
405 try: name=urllib.unquote_plus(params["name"])
406 except: pass
407 try: mode=int(params["mode"])
408 except: pass
409 try: id=int(params["id"])
410 except: pass
411
412 if (id > 0):
413 lastID = id
414
415 if mode==None:
416 grooveshark.categories()
417
418 elif mode==MODE_SEARCH_SONGS:
419 grooveshark.searchSongs()
420
421 elif mode==MODE_SEARCH_ALBUMS:
422 grooveshark.searchAlbums()
423
424 elif mode==MODE_SEARCH_ARTISTS:
425 grooveshark.searchArtists()
426
427 elif mode==MODE_POPULAR:
428 grooveshark.popular()
429
430 elif mode==MODE_PLAYLISTS:
431 grooveshark.playlists()
432
433 elif mode==MODE_FAVORITES:
434 grooveshark.favorites()
435
436 elif mode==MODE_SONG:
437 try: name=urllib.unquote_plus(params["name"])
438 except: pass
439 try: album=urllib.unquote_plus(params["album"])
440 except: pass
441 try: artist=urllib.unquote_plus(params["artist"])
442 except: pass
443 try: duration=int(params["duration"])
444 except: pass
445 try: thumb=urllib.unquote_plus(params["thumb"])
446 except: pass
447 try: image=urllib.unquote_plus(params["image"])
448 except: pass
449 song = grooveshark.songItem(id, name, album, artist, duration, thumb, image)
450 grooveshark.playSong(song)
451
452 elif mode==MODE_ARTIST:
453 grooveshark.artist(lastID)
454
455 elif mode==MODE_ALBUM:
456 grooveshark.album(lastID)
457
458 elif mode==MODE_PLAYLIST:
459 grooveshark.playlist(lastID)
460
461 elif mode==MODE_FAVORITE:
462 grooveshark.favorite(lastID)
463
464 elif mode==MODE_UNFAVORITE:
465 grooveshark.unfavorite(lastID)
466
467 elif mode==MODE_SIMILAR_ARTISTS:
468 grooveshark.similarArtists(lastID)
469
470 if (mode < MODE_SONG):
471 xbmcplugin.endOfDirectory(int(sys.argv[1]))