4e8377726399523a04c59479266403718927105a
[clinton/xbmc-groove.git] / default.py
1 # Copyright 2011 Stephen Denham
2
3 # This file is part of xbmc-groove.
4 #
5 # xbmc-groove is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # xbmc-groove is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with xbmc-groove. If not, see <http://www.gnu.org/licenses/>.
17
18
19 import urllib, sys, os, shutil, re, pickle, time, tempfile, xbmcaddon, xbmcplugin, xbmcgui, xbmc
20
21 __addon__ = xbmcaddon.Addon('plugin.audio.groove')
22 __addonname__ = __addon__.getAddonInfo('name')
23 __cwd__ = __addon__.getAddonInfo('path')
24 __author__ = __addon__.getAddonInfo('author')
25 __version__ = __addon__.getAddonInfo('version')
26 __language__ = __addon__.getLocalizedString
27 __debugging__ = __addon__.getSetting('debug')
28
29 MODE_SEARCH_SONGS = 1
30 MODE_SEARCH_ALBUMS = 2
31 MODE_SEARCH_ARTISTS = 3
32 MODE_SEARCH_ARTISTS_ALBUMS = 4
33 MODE_SEARCH_PLAYLISTS = 5
34 MODE_ARTIST_POPULAR = 6
35 MODE_POPULAR_SONGS = 7
36 MODE_FAVORITES = 8
37 MODE_PLAYLISTS = 9
38 MODE_ALBUM = 10
39 MODE_ARTIST = 11
40 MODE_PLAYLIST = 12
41 MODE_SONG_PAGE = 13
42 MODE_SIMILAR_ARTISTS = 14
43 MODE_SONG = 15
44 MODE_FAVORITE = 16
45 MODE_UNFAVORITE = 17
46 MODE_MAKE_PLAYLIST = 18
47 MODE_REMOVE_PLAYLIST = 19
48 MODE_RENAME_PLAYLIST = 20
49 MODE_REMOVE_PLAYLIST_SONG = 21
50 MODE_ADD_PLAYLIST_SONG = 22
51
52 ACTION_MOVE_LEFT = 1
53 ACTION_MOVE_UP = 3
54 ACTION_MOVE_DOWN = 4
55 ACTION_PAGE_UP = 5
56 ACTION_PAGE_DOWN = 6
57 ACTION_SELECT_ITEM = 7
58 ACTION_PREVIOUS_MENU = 10
59
60 # Formats for track labels
61 ARTIST_ALBUM_NAME_LABEL = 0
62 NAME_ALBUM_ARTIST_LABEL = 1
63
64 # Stream marking time (seconds)
65 STREAM_MARKING_TIME = 30
66
67 # Timeout
68 STREAM_TIMEOUT = 30
69
70 songMarkTime = 0
71 player = xbmc.Player()
72 playTimer = None
73
74 baseDir = __cwd__
75 resDir = xbmc.translatePath(os.path.join(baseDir, 'resources'))
76 libDir = xbmc.translatePath(os.path.join(resDir, 'lib'))
77 imgDir = xbmc.translatePath(os.path.join(resDir, 'img'))
78 cacheDir = os.path.join(xbmc.translatePath('special://masterprofile/addon_data/'), os.path.basename(baseDir))
79 thumbDirName = 'thumb'
80 thumbDir = os.path.join(xbmc.translatePath('special://masterprofile/addon_data/'), os.path.basename(baseDir), thumbDirName)
81
82 baseModeUrl = 'plugin://plugin.audio.groove/'
83 playlistUrl = baseModeUrl + '?mode=' + str(MODE_PLAYLIST)
84 playlistsUrl = baseModeUrl + '?mode=' + str(MODE_PLAYLISTS)
85 favoritesUrl = baseModeUrl + '?mode=' + str(MODE_FAVORITES)
86
87 searchArtistsAlbumsName = __language__(30006)
88
89 thumbDef = os.path.join(imgDir, 'default.tbn')
90 listBackground = os.path.join(imgDir, 'listbackground.png')
91
92 sys.path.append (libDir)
93 from GroovesharkAPI import GrooveAPI
94 from threading import Event, Thread
95
96 if __debugging__ == 'true':
97 __debugging__ = True
98 else:
99 __debugging__ = False
100
101 try:
102 groovesharkApi = GrooveAPI(__debugging__)
103 if groovesharkApi.pingService() != True:
104 raise StandardError(__language__(30007))
105 except:
106 dialog = xbmcgui.Dialog(__language__(30008),__language__(30009),__language__(30010))
107 dialog.ok(__language__(30008),__language__(30009))
108 sys.exit(-1)
109
110 # Mark song as playing or played
111 def markSong(songid, duration, streamKey, streamServerID):
112 global songMarkTime
113 global playTimer
114 global player
115 if player.isPlayingAudio():
116 tNow = player.getTime()
117 if tNow >= STREAM_MARKING_TIME and songMarkTime == 0:
118 groovesharkApi.markStreamKeyOver30Secs(streamKey, streamServerID)
119 songMarkTime = tNow
120 elif duration > tNow and duration - tNow < 2 and songMarkTime >= STREAM_MARKING_TIME:
121 playTimer.cancel()
122 songMarkTime = 0
123 groovesharkApi.markSongComplete(songid, streamKey, streamServerID)
124 else:
125 playTimer.cancel()
126 songMarkTime = 0
127
128 class _Info:
129 def __init__( self, *args, **kwargs ):
130 self.__dict__.update( kwargs )
131
132 # Window dialog to select a grooveshark playlist
133 class GroovesharkPlaylistSelect(xbmcgui.WindowDialog):
134
135 def __init__(self, items=[]):
136 gap = int(self.getHeight()/100)
137 w = int(self.getWidth()*0.5)
138 h = self.getHeight()-30*gap
139 rw = self.getWidth()
140 rh = self.getHeight()
141 x = rw/2 - w/2
142 y = rh/2 -h/2
143
144 self.imgBg = xbmcgui.ControlImage(x+gap, 5*gap+y, w-2*gap, h-5*gap, listBackground)
145 self.addControl(self.imgBg)
146
147 self.playlistControl = xbmcgui.ControlList(2*gap+x, y+3*gap+30, w-4*gap, h-10*gap, textColor='0xFFFFFFFF', selectedColor='0xFFFF4242')
148 self.playlistControl.setItemHeight(50)
149 self.addControl(self.playlistControl)
150
151 self.lastPos = 0
152 self.isSelecting = False
153 self.selected = -1
154 listitems = []
155 for playlist in items:
156 listitems.append(xbmcgui.ListItem(playlist[0]))
157 listitems.append(xbmcgui.ListItem(__language__(30011)))
158 self.playlistControl.addItems(listitems)
159 self.setFocus(self.playlistControl)
160 self.playlistControl.selectItem(0)
161 item = self.playlistControl.getListItem(self.lastPos)
162 item.select(True)
163
164 # Highlight selected item
165 def setHighlight(self):
166 if self.isSelecting:
167 return
168 else:
169 self.isSelecting = True
170
171 pos = self.playlistControl.getSelectedPosition()
172 if pos >= 0:
173 item = self.playlistControl.getListItem(self.lastPos)
174 item.select(False)
175 item = self.playlistControl.getListItem(pos)
176 item.select(True)
177 self.lastPos = pos
178 self.isSelecting = False
179
180 # Control - select
181 def onControl(self, control):
182 if control == self.playlistControl:
183 self.selected = self.playlistControl.getSelectedPosition()
184 self.close()
185
186 # Action - close or up/down
187 def onAction(self, action):
188 if action == ACTION_PREVIOUS_MENU:
189 self.selected = -1
190 self.close()
191 elif action == ACTION_MOVE_UP or action == ACTION_MOVE_DOWN or action == ACTION_PAGE_UP or action == ACTION_PAGE_DOWN == 6:
192 self.setFocus(self.playlistControl)
193 self.setHighlight()
194
195
196 class PlayTimer(Thread):
197 # interval -- floating point number specifying the number of seconds to wait before executing function
198 # function -- the function (or callable object) to be executed
199
200 # iterations -- integer specifying the number of iterations to perform
201 # args -- list of positional arguments passed to function
202 # kwargs -- dictionary of keyword arguments passed to function
203
204 def __init__(self, interval, function, iterations=0, args=[], kwargs={}):
205 Thread.__init__(self)
206 self.interval = interval
207 self.function = function
208 self.iterations = iterations
209 self.args = args
210 self.kwargs = kwargs
211 self.finished = Event()
212
213 def run(self):
214 count = 0
215 while not self.finished.isSet() and (self.iterations <= 0 or count < self.iterations):
216 self.finished.wait(self.interval)
217 if not self.finished.isSet():
218 self.function(*self.args, **self.kwargs)
219 count += 1
220
221 def cancel(self):
222 self.finished.set()
223
224 def setIterations(self, iterations):
225 self.iterations = iterations
226
227
228 def getTime(self):
229 return self.iterations * self.interval
230
231
232 class Grooveshark:
233
234 albumImg = xbmc.translatePath(os.path.join(imgDir, 'album.png'))
235 artistImg = xbmc.translatePath(os.path.join(imgDir, 'artist.png'))
236 artistsAlbumsImg = xbmc.translatePath(os.path.join(imgDir, 'artistsalbums.png'))
237 favoritesImg = xbmc.translatePath(os.path.join(imgDir, 'favorites.png'))
238 playlistImg = xbmc.translatePath(os.path.join(imgDir, 'playlist.png'))
239 usersplaylistsImg = xbmc.translatePath(os.path.join(imgDir, 'usersplaylists.png'))
240 popularSongsImg = xbmc.translatePath(os.path.join(imgDir, 'popularSongs.png'))
241 popularSongsArtistImg = xbmc.translatePath(os.path.join(imgDir, 'popularSongsArtist.png'))
242 songImg = xbmc.translatePath(os.path.join(imgDir, 'song.png'))
243 defImg = xbmc.translatePath(os.path.join(imgDir, 'default.tbn'))
244 fanImg = xbmc.translatePath(os.path.join(baseDir, 'fanart.jpg'))
245
246 settings = xbmcaddon.Addon(id='plugin.audio.groove')
247 songsearchlimit = int(settings.getSetting('songsearchlimit'))
248 albumsearchlimit = int(settings.getSetting('albumsearchlimit'))
249 artistsearchlimit = int(settings.getSetting('artistsearchlimit'))
250 songspagelimit = int(settings.getSetting('songspagelimit'))
251 username = settings.getSetting('username')
252 password = settings.getSetting('password')
253
254 userid = 0
255
256 def __init__( self ):
257 self._handle = int(sys.argv[1])
258 if os.path.isdir(cacheDir) == False:
259 os.makedirs(cacheDir)
260 if __debugging__ :
261 xbmc.log(__language__(30012) + " " + cacheDir)
262 artDir = xbmc.translatePath(thumbDir)
263 if os.path.isdir(artDir) == False:
264 os.makedirs(artDir)
265 if __debugging__ :
266 xbmc.log(__language__(30012) + " " + artDir)
267
268 # Top-level menu
269 def categories(self):
270
271 self.userid = self._get_login()
272
273 # Setup
274 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
275
276 self._add_dir(__language__(30013), '', MODE_SEARCH_SONGS, self.songImg, 0)
277 self._add_dir(__language__(30014), '', MODE_SEARCH_ALBUMS, self.albumImg, 0)
278 self._add_dir(__language__(30015), '', MODE_SEARCH_ARTISTS, self.artistImg, 0)
279 self._add_dir(searchArtistsAlbumsName, '', MODE_SEARCH_ARTISTS_ALBUMS, self.artistsAlbumsImg, 0)
280 # Not supported by key
281 #self._add_dir("Search for user's playlists...", '', MODE_SEARCH_PLAYLISTS, self.usersplaylistsImg, 0)
282 self._add_dir(__language__(30016), '', MODE_ARTIST_POPULAR, self.popularSongsArtistImg, 0)
283 self._add_dir(__language__(30017), '', MODE_POPULAR_SONGS, self.popularSongsImg, 0)
284 if (self.userid != 0):
285 self._add_dir(__language__(30018), '', MODE_FAVORITES, self.favoritesImg, 0)
286 self._add_dir(__language__(30019), '', MODE_PLAYLISTS, self.playlistImg, 0)
287
288 # Search for songs
289 def searchSongs(self):
290 query = self._get_keyboard(default="", heading=__language__(30020))
291 if (query != ''):
292 songs = groovesharkApi.getSongSearchResults(query, limit = self.songsearchlimit)
293 if (len(songs) > 0):
294 self._add_songs_directory(songs)
295 else:
296 dialog = xbmcgui.Dialog()
297 dialog.ok(__language__(30008), __language__(30021))
298 self.categories()
299 else:
300 self.categories()
301
302 # Search for albums
303 def searchAlbums(self):
304 query = self._get_keyboard(default="", heading=__language__(30022))
305 if (query != ''):
306 albums = groovesharkApi.getAlbumSearchResults(query, limit = self.albumsearchlimit)
307 if (len(albums) > 0):
308 self._add_albums_directory(albums)
309 else:
310 dialog = xbmcgui.Dialog()
311 dialog.ok(__language__(30008), __language__(30023))
312 self.categories()
313 else:
314 self.categories()
315
316 # Search for artists
317 def searchArtists(self):
318 query = self._get_keyboard(default="", heading=__language__(30024))
319 if (query != ''):
320 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
321 if (len(artists) > 0):
322 self._add_artists_directory(artists)
323 else:
324 dialog = xbmcgui.Dialog()
325 dialog.ok(__language__(30008), __language__(30025))
326 self.categories()
327 else:
328 self.categories()
329
330 # Search for playlists
331 def searchPlaylists(self):
332 query = self._get_keyboard(default="", heading=__language__(30026))
333 if (query != ''):
334 playlists = groovesharkApi.getUserPlaylistsByUsername(query)
335 if (len(playlists) > 0):
336 self._add_playlists_directory(playlists)
337 else:
338 dialog = xbmcgui.Dialog()
339 dialog.ok(__language__(30008), __language__(30027))
340 self.categories()
341 else:
342 self.categories()
343
344 # Search for artists albums
345 def searchArtistsAlbums(self, artistName = None):
346 if artistName == None or artistName == searchArtistsAlbumsName:
347 query = self._get_keyboard(default="", heading=__language__(30028))
348 else:
349 query = artistName
350 if (query != ''):
351 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
352 if (len(artists) > 0):
353 artist = artists[0]
354 artistID = artist[1]
355 if __debugging__ :
356 xbmc.log("Found " + artist[0] + "...")
357 albums = groovesharkApi.getArtistAlbums(artistID, self.albumsearchlimit)
358 if (len(albums) > 0):
359 self._add_albums_directory(albums, artistID)
360 else:
361 dialog = xbmcgui.Dialog()
362 dialog.ok(__language__(30008), __language__(30029))
363 self.categories()
364 else:
365 dialog = xbmcgui.Dialog()
366 dialog.ok(__language__(30008), __language__(30030))
367 self.categories()
368 else:
369 self.categories()
370
371 # Get my favorites
372 def favorites(self):
373 userid = self._get_login()
374 if (userid != 0):
375 favorites = groovesharkApi.getUserFavoriteSongs()
376 if (len(favorites) > 0):
377 self._add_songs_directory(favorites, isFavorites=True)
378 else:
379 dialog = xbmcgui.Dialog()
380 dialog.ok(__language__(30008), __language__(30031))
381 self.categories()
382
383 # Get popular songs
384 def popularSongs(self):
385 popular = groovesharkApi.getPopularSongsToday(limit = self.songsearchlimit)
386 if (len(popular) > 0):
387 self._add_songs_directory(popular)
388 else:
389 dialog = xbmcgui.Dialog()
390 dialog.ok(__language__(30008), __language__(30032))
391 self.categories()
392
393 # Get my playlists
394 def playlists(self):
395 userid = self._get_login()
396 if (userid != 0):
397 playlists = groovesharkApi.getUserPlaylists()
398 if (len(playlists) > 0):
399 self._add_playlists_directory(playlists)
400 else:
401 dialog = xbmcgui.Dialog()
402 dialog.ok(__language__(30008), __language__(30033))
403 self.categories()
404 else:
405 dialog = xbmcgui.Dialog()
406 dialog.ok(__language__(30008), __language__(30034), __language__(30035))
407
408 # Make songs a favorite
409 def favorite(self, songid):
410 userid = self._get_login()
411 if (userid != 0):
412 if __debugging__ :
413 xbmc.log("Favorite song: " + str(songid))
414 groovesharkApi.addUserFavoriteSong(songID = songid)
415 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30036) + ', 1000, ' + thumbDef + ')')
416 else:
417 dialog = xbmcgui.Dialog()
418 dialog.ok(__language__(30008), __language__(30034), __language__(30037))
419
420 # Remove song from favorites
421 def unfavorite(self, songid, prevMode=0):
422 userid = self._get_login()
423 if (userid != 0):
424 if __debugging__ :
425 xbmc.log("Unfavorite song: " + str(songid) + ', previous mode was ' + str(prevMode))
426 groovesharkApi.removeUserFavoriteSongs(songIDs = songid)
427 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30038) + ', 1000, ' + thumbDef + ')')
428 # Refresh to remove item from directory
429 if (int(prevMode) == MODE_FAVORITES):
430 xbmc.executebuiltin("Container.Refresh(" + favoritesUrl + ")")
431 else:
432 dialog = xbmcgui.Dialog()
433 dialog.ok(__language__(30008), __language__(30034), __language__(30039))
434
435
436 # Show selected album
437 def album(self, albumid):
438 album = groovesharkApi.getAlbumSongs(albumid, limit = self.songsearchlimit)
439 self._add_songs_directory(album, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL)
440
441 # Show selected artist
442 def artist(self, artistid):
443 albums = groovesharkApi.getArtistAlbums(artistid, limit = self.albumsearchlimit)
444 self._add_albums_directory(albums, artistid, True)
445
446 # Show selected playlist
447 def playlist(self, playlistid, playlistname):
448 userid = self._get_login()
449 if (userid != 0):
450 songs = groovesharkApi.getPlaylistSongs(playlistid)
451 self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL, playlistid=playlistid, playlistname=playlistname)
452 else:
453 dialog = xbmcgui.Dialog()
454 dialog.ok(__language__(30008), __language__(30034), __language__(30040))
455
456 # Show popular songs of the artist
457 def artistPopularSongs(self):
458 query = self._get_keyboard(default="", heading=__language__(30041))
459 if (query != ''):
460 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
461 if (len(artists) > 0):
462 artist = artists[0]
463 artistID = artist[1]
464 if __debugging__ :
465 xbmc.log("Found " + artist[0] + "...")
466 songs = groovesharkApi.getArtistPopularSongs(artistID, limit = self.songsearchlimit)
467 if (len(songs) > 0):
468 self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL)
469 else:
470 dialog = xbmcgui.Dialog()
471 dialog.ok(__language__(30008), __language__(30042))
472 self.categories()
473 else:
474 dialog = xbmcgui.Dialog()
475 dialog.ok(__language__(30008), __language__(30043))
476 self.categories()
477 else:
478 self.categories()
479
480 # Play a song
481 def playSong(self, item):
482 global playTimer
483 global player
484 if item != None:
485 # Get stream as it could have expired
486 item.select(True)
487 url = ''
488 songid = item.getProperty('songid')
489 stream = groovesharkApi.getSubscriberStreamKey(songid)
490 if stream != False:
491 url = stream['url']
492 key = stream['StreamKey']
493 server = stream['StreamServerID']
494 duration = int(self._setDuration(stream['uSecs']))
495 stream = [songid, duration, url, key, server]
496 self._setSongStream(stream)
497 if url != '':
498 item.setPath(url)
499 xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)
500 if __debugging__ :
501 xbmc.log("Grooveshark playing: " + url)
502 # Wait for play then start timer
503 seconds = 0
504 while seconds < STREAM_TIMEOUT:
505 try:
506 if player.isPlayingAudio() == True:
507 if playTimer != None:
508 playTimer.cancel()
509 songMarkTime = 0
510 playTimer = PlayTimer(1, markSong, self._setDuration(duration), [songid, duration, key, server])
511 playTimer.start()
512 break
513 except: pass
514 time.sleep(1)
515 seconds = seconds + 1
516 else:
517 xbmc.log("No song URL")
518 else:
519 xbmc.log("No song stream")
520 else:
521 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30044) + ', 1000, ' + thumbDef + ')')
522
523 # Make a song directory item
524 def songItem(self, songid, name, album, artist, coverart, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, tracknumber=1):
525
526 stream = self._getSongStream(songid)
527 if stream != False:
528 duration = stream[1]
529 url = stream[2]
530 key = stream[3]
531 server = stream[4]
532 songImg = self._get_icon(coverart, 'song-' + str(songid) + "-image")
533 if int(trackLabelFormat) == NAME_ALBUM_ARTIST_LABEL:
534 trackLabel = name + " - " + album + " - " + artist
535 else:
536 trackLabel = artist + " - " + album + " - " + name
537 item = xbmcgui.ListItem(label = trackLabel, thumbnailImage=songImg, iconImage=songImg)
538 item.setPath(url)
539 item.setInfo( type="music", infoLabels={ "title": name, "album": album, "artist": artist, "duration": duration, "tracknumber" : tracknumber} )
540 item.setProperty('mimetype', 'audio/mpeg')
541 item.setProperty("IsPlayable", "true")
542 item.setProperty('songid', str(songid))
543 item.setProperty('coverart', songImg)
544 item.setProperty('title', name)
545 item.setProperty('album', album)
546 item.setProperty('artist', artist)
547 item.setProperty('duration', str(duration))
548 item.setProperty('key', str(key))
549 item.setProperty('server', str(server))
550 return item
551 else:
552 xbmc.log("No song URL")
553 return None
554
555 # Next page of songs
556 def songPage(self, offset, trackLabelFormat, playlistid = 0, playlistname = ''):
557 self._add_songs_directory([], trackLabelFormat, offset, playlistid = playlistid, playlistname = playlistname)
558
559 # Make a playlist from an album
560 def makePlaylist(self, albumid, name):
561 userid = self._get_login()
562 if (userid != 0):
563 re.split(' - ',name,1)
564 nameTokens = re.split(' - ',name,1) # suggested name
565 name = self._get_keyboard(default=nameTokens[0], heading=__language__(30045))
566 if name != '':
567 album = groovesharkApi.getAlbumSongs(albumid, limit = self.songsearchlimit)
568 songids = []
569 for song in album:
570 songids.append(song[1])
571 if groovesharkApi.createPlaylist(name, songids) == 0:
572 dialog = xbmcgui.Dialog()
573 dialog.ok(__language__(30008), __language__(30046), name)
574 else:
575 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30047)+ ', 1000, ' + thumbDef + ')')
576 else:
577 dialog = xbmcgui.Dialog()
578 dialog.ok(__language__(30008), __language__(30034), __language__(30048))
579
580 # Rename a playlist
581 def renamePlaylist(self, playlistid, name):
582 userid = self._get_login()
583 if (userid != 0):
584 newname = self._get_keyboard(default=name, heading=__language__(30049))
585 if newname == '':
586 return
587 elif groovesharkApi.playlistRename(playlistid, newname) == 0:
588 dialog = xbmcgui.Dialog()
589 dialog.ok(__language__(30008), __language__(30050), name)
590 else:
591 # Refresh to show new item name
592 xbmc.executebuiltin("Container.Refresh")
593 else:
594 dialog = xbmcgui.Dialog()
595 dialog.ok(__language__(30008), __language__(30034), __language__(30051))
596
597 # Remove a playlist
598 def removePlaylist(self, playlistid, name):
599 dialog = xbmcgui.Dialog()
600 if dialog.yesno(__language__(30008), name, __language__(30052)) == True:
601 userid = self._get_login()
602 if (userid != 0):
603 if groovesharkApi.playlistDelete(playlistid) == 0:
604 dialog = xbmcgui.Dialog()
605 dialog.ok(__language__(30008), __language__(30053), name)
606 else:
607 # Refresh to remove item from directory
608 xbmc.executebuiltin("Container.Refresh(" + playlistsUrl + ")")
609 else:
610 dialog = xbmcgui.Dialog()
611 dialog.ok(__language__(30008), __language__(30034), __language__(30054))
612
613 # Add song to playlist
614 def addPlaylistSong(self, songid):
615 userid = self._get_login()
616 if (userid != 0):
617 playlists = groovesharkApi.getUserPlaylists()
618 if (len(playlists) > 0):
619 ret = 0
620 # Select the playlist
621 playlistSelect = GroovesharkPlaylistSelect(items=playlists)
622 playlistSelect.setFocus(playlistSelect.playlistControl)
623 playlistSelect.doModal()
624 i = playlistSelect.selected
625 del playlistSelect
626 if i > -1:
627 # Add a new playlist
628 if i >= len(playlists):
629 name = self._get_keyboard(default='', heading=__language__(30055))
630 if name != '':
631 songIds = []
632 songIds.append(songid)
633 if groovesharkApi.createPlaylist(name, songIds) == 0:
634 dialog = xbmcgui.Dialog()
635 dialog.ok(__language__(30008), __language__(30056), name)
636 else:
637 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30057) + ', 1000, ' + thumbDef + ')')
638 # Existing playlist
639 else:
640 playlist = playlists[i]
641 playlistid = playlist[1]
642 if __debugging__ :
643 xbmc.log("Add song " + str(songid) + " to playlist " + str(playlistid))
644 songIDs=[]
645 songs = groovesharkApi.getPlaylistSongs(playlistid)
646 for song in songs:
647 songIDs.append(song[1])
648 songIDs.append(songid)
649 ret = groovesharkApi.setPlaylistSongs(playlistid, songIDs)
650 if ret == False:
651 dialog = xbmcgui.Dialog()
652 dialog.ok(__language__(30008), __language__(30058))
653 else:
654 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30059) + ', 1000, ' + thumbDef + ')')
655 else:
656 dialog = xbmcgui.Dialog()
657 dialog.ok(__language__(30008), __language__(30060))
658 self.categories()
659 else:
660 dialog = xbmcgui.Dialog()
661 dialog.ok(__language__(30008), __language__(30034), __language__(30061))
662
663 # Remove song from playlist
664 def removePlaylistSong(self, playlistid, playlistname, songid):
665 dialog = xbmcgui.Dialog()
666 if dialog.yesno(__language__(30008), __language__(30062), __language__(30063)) == True:
667 userid = self._get_login()
668 if (userid != 0):
669 songs = groovesharkApi.getPlaylistSongs(playlistID)
670 songIDs=[]
671 for song in songs:
672 if (song[1] != songid):
673 songIDs.append(song[1])
674 ret = groovesharkApi.setPlaylistSongs(playlistID, songIDs)
675 if ret == False:
676 dialog = xbmcgui.Dialog()
677 dialog.ok(__language__(30008), __language__(30064), __language__(30065))
678 else:
679 # Refresh to remove item from directory
680 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30066)+ ', 1000, ' + thumbDef + ')')
681 xbmc.executebuiltin("Container.Update(" + playlistUrl + "&id="+str(playlistid) + "&name=" + str(playlistname) + ")")
682 else:
683 dialog = xbmcgui.Dialog()
684 dialog.ok(__language__(30008), __language__(30034), __language__(30067))
685
686 # Find similar artists to searched artist
687 def similarArtists(self, artistId):
688 similar = groovesharkApi.getSimilarArtists(artistId, limit = self.artistsearchlimit)
689 if (len(similar) > 0):
690 self._add_artists_directory(similar)
691 else:
692 dialog = xbmcgui.Dialog()
693 dialog.ok(__language__(30008), __language__(30068))
694 self.categories()
695
696 # Get keyboard input
697 def _get_keyboard(self, default="", heading="", hidden=False):
698 kb = xbmc.Keyboard(default, heading, hidden)
699 kb.doModal()
700 if (kb.isConfirmed()):
701 return unicode(kb.getText(), "utf-8")
702 return ''
703
704 # Login to grooveshark
705 def _get_login(self):
706 if (self.username == "" or self.password == ""):
707 dialog = xbmcgui.Dialog()
708 dialog.ok(__language__(30008), __language__(30069), __language__(30070), __language__(30082))
709 return 0
710 else:
711 if self.userid == 0:
712 uid = groovesharkApi.login(self.username, self.password)
713 if (uid != 0):
714 return uid
715 else:
716 dialog = xbmcgui.Dialog()
717 dialog.ok(__language__(30008), __language__(30069), __language__(30070), __language__(30082))
718 return 0
719
720 # File download
721 def _get_icon(self, url, songid):
722 if url != 'None':
723 localThumb = os.path.join(xbmc.translatePath(os.path.join(thumbDir, str(songid)))) + '.tbn'
724 try:
725 if os.path.isfile(localThumb) == False:
726 loc = urllib.URLopener()
727 loc.retrieve(url, localThumb)
728 except:
729 shutil.copy2(thumbDef, localThumb)
730 return os.path.join(os.path.join(thumbDir, str(songid))) + '.tbn'
731 else:
732 return thumbDef
733
734 # Add songs to directory
735 def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, offset=0, playlistid=0, playlistname='', isFavorites=False):
736
737 totalSongs = len(songs)
738 offset = int(offset)
739 start = 0
740 end = totalSongs
741
742 # No pages needed
743 if offset == 0 and totalSongs <= self.songspagelimit:
744 if __debugging__ :
745 xbmc.log("Found " + str(totalSongs) + " songs...")
746 # Pages
747 else:
748 # Cache all next pages songs
749 if offset == 0:
750 self._setSavedSongs(songs)
751 else:
752 songs = self._getSavedSongs()
753 totalSongs = len(songs)
754
755 if totalSongs > 0:
756 start = offset
757 end = min(start + self.songspagelimit,totalSongs)
758
759 n = start
760 items = end - start
761 while n < end:
762 song = songs[n]
763 name = song[0]
764 songid = song[1]
765 album = song[2]
766 artist = song[4]
767 coverart = song[6]
768 item = self.songItem(songid, name, album, artist, coverart, trackLabelFormat, (n+1))
769 if item != None:
770 coverart = item.getProperty('coverart')
771 songname = song[0]
772 songalbum = song[2]
773 songartist = song[4]
774 u=sys.argv[0]+"?mode="+str(MODE_SONG)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid) \
775 +"&album="+urllib.quote_plus(songalbum) \
776 +"&artist="+urllib.quote_plus(songartist) \
777 +"&coverart="+urllib.quote_plus(coverart)
778 fav=sys.argv[0]+"?mode="+str(MODE_FAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
779 unfav=sys.argv[0]+"?mode="+str(MODE_UNFAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)+"&prevmode="
780 menuItems = []
781 if isFavorites == True:
782 unfav = unfav +str(MODE_FAVORITES)
783 else:
784 menuItems.append((__language__(30071), "XBMC.RunPlugin("+fav+")"))
785 menuItems.append((__language__(30072), "XBMC.RunPlugin("+unfav+")"))
786 if playlistid > 0:
787 rmplaylstsong=sys.argv[0]+"?playlistid="+str(playlistid)+"&id="+str(songid)+"&mode="+str(MODE_REMOVE_PLAYLIST_SONG)+"&name="+str(playlistname)
788 menuItems.append((__language__(30073), "XBMC.RunPlugin("+rmplaylstsong+")"))
789 else:
790 addplaylstsong=sys.argv[0]+"?id="+str(songid)+"&mode="+str(MODE_ADD_PLAYLIST_SONG)
791 menuItems.append((__language__(30074), "XBMC.RunPlugin("+addplaylstsong+")"))
792 item.addContextMenuItems(menuItems, replaceItems=False)
793 xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False, totalItems=items)
794 else:
795 end = min(end + 1,totalSongs)
796 if __debugging__ :
797 xbmc.log(song[0] + " does not exist.")
798 n = n + 1
799
800 if totalSongs > end:
801 u=sys.argv[0]+"?mode="+str(MODE_SONG_PAGE)+"&id=playlistid"+"&offset="+str(end)+"&label="+str(trackLabelFormat)+"&name="+str(playlistname)
802 self._add_dir(__language__(30075) + '...', u, MODE_SONG_PAGE, self.songImg, 0, totalSongs - end)
803
804 xbmcplugin.setContent(self._handle, 'songs')
805 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
806
807 # Add albums to directory
808 def _add_albums_directory(self, albums, artistid=0, isverified=False):
809 n = len(albums)
810 itemsExisting = n
811 if __debugging__ :
812 xbmc.log("Found " + str(n) + " albums...")
813 i = 0
814 while i < n:
815 album = albums[i]
816 albumID = album[3]
817 if isverified or groovesharkApi.getDoesAlbumExist(albumID):
818 albumArtistName = album[0]
819 albumName = album[2]
820 albumImage = self._get_icon(album[4], 'album-' + str(albumID))
821 self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID, itemsExisting)
822 else:
823 itemsExisting = itemsExisting - 1
824 i = i + 1
825 # Not supported by key
826 #if artistid > 0:
827 # self._add_dir('Similar artists...', '', MODE_SIMILAR_ARTISTS, self.artistImg, artistid)
828 xbmcplugin.setContent(self._handle, 'albums')
829 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE)
830 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
831
832 # Add artists to directory
833 def _add_artists_directory(self, artists):
834 n = len(artists)
835 itemsExisting = n
836 if __debugging__ :
837 xbmc.log("Found " + str(n) + " artists...")
838 i = 0
839 while i < n:
840 artist = artists[i]
841 artistID = artist[1]
842 if groovesharkApi.getDoesArtistExist(artistID):
843 artistName = artist[0]
844 self._add_dir(artistName, '', MODE_ARTIST, self.artistImg, artistID, itemsExisting)
845 else:
846 itemsExisting = itemsExisting - 1
847 i = i + 1
848 xbmcplugin.setContent(self._handle, 'artists')
849 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE)
850 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
851
852 # Add playlists to directory
853 def _add_playlists_directory(self, playlists):
854 n = len(playlists)
855 if __debugging__ :
856 xbmc.log("Found " + str(n) + " playlists...")
857 i = 0
858 while i < n:
859 playlist = playlists[i]
860 playlistName = playlist[0]
861 playlistID = playlist[1]
862 self._add_dir(playlistName, '', MODE_PLAYLIST, self.playlistImg, playlistID, n)
863 i = i + 1
864 xbmcplugin.setContent(self._handle, 'files')
865 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_LABEL)
866 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
867
868 # Add whatever directory
869 def _add_dir(self, name, url, mode, iconimage, itemId, items=1):
870
871 if url == '':
872 u=sys.argv[0]+"?mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(itemId)
873 else:
874 u = url
875 directory=xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
876 directory.setInfo( type="Music", infoLabels={ "title": name } )
877
878 # Custom menu items
879 menuItems = []
880 if mode == MODE_ALBUM:
881 mkplaylst=sys.argv[0]+"?mode="+str(MODE_MAKE_PLAYLIST)+"&name="+name+"&id="+str(itemId)
882 menuItems.append((__language__(30076), "XBMC.RunPlugin("+mkplaylst+")"))
883 if mode == MODE_PLAYLIST:
884 rmplaylst=sys.argv[0]+"?mode="+str(MODE_REMOVE_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(itemId)
885 menuItems.append((__language__(30077), "XBMC.RunPlugin("+rmplaylst+")"))
886 mvplaylst=sys.argv[0]+"?mode="+str(MODE_RENAME_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(itemId)
887 menuItems.append((__language__(30078), "XBMC.RunPlugin("+mvplaylst+")"))
888
889 directory.addContextMenuItems(menuItems, replaceItems=False)
890
891 return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=directory,isFolder=True, totalItems=items)
892
893 def _getSavedSongs(self):
894 path = os.path.join(cacheDir, 'songs.dmp')
895 try:
896 f = open(path, 'rb')
897 songs = pickle.load(f)
898 f.close()
899 except:
900 songs = []
901 pass
902 return songs
903
904 def _setSavedSongs(self, songs):
905 try:
906 # Create the 'data' directory if it doesn't exist.
907 if not os.path.exists(cacheDir):
908 os.makedirs(cacheDir)
909 path = os.path.join(cacheDir, 'songs.dmp')
910 f = open(path, 'wb')
911 pickle.dump(songs, f, protocol=pickle.HIGHEST_PROTOCOL)
912 f.close()
913 except:
914 xbmc.log("An error occurred saving songs")
915 pass
916
917 # Duration to seconds
918 def _setDuration(self, usecs):
919 if usecs < 60000000:
920 usecs = usecs * 10 # Some durations are 10x to small
921 return int(usecs / 1000000)
922
923 def _getSongStream(self, songid):
924 idSong = int(songid)
925 stream = None
926 streams = []
927 path = os.path.join(cacheDir, 'streams.dmp')
928 try:
929 f = open(path, 'rb')
930 streams = pickle.load(f)
931 for song in streams:
932 if song[0] == idSong:
933 duration = song[1]
934 url = song[2]
935 key = song[3]
936 server = song[4]
937 stream = [idSong, duration, url, key, server]
938 if __debugging__ :
939 xbmc.log("Found " + str(idSong) + " in stream cache")
940 break;
941 f.close()
942 except:
943 pass
944
945 # Not in cache
946 if stream == None:
947 stream = groovesharkApi.getSubscriberStreamKey(songid)
948 if stream != False and stream['url'] != '':
949 duration = self._setDuration(stream['uSecs'])
950 url = stream['url']
951 key = stream['StreamKey']
952 server = stream['StreamServerID']
953 stream = [idSong, duration, url, key, server]
954 self._addSongStream(stream)
955
956 return stream
957
958 def _addSongStream(self, stream):
959 streams = self._getStreams()
960 streams.append(stream)
961 path = os.path.join(cacheDir, 'streams.dmp')
962 try:
963 f = open(path, 'wb')
964 pickle.dump(streams, f, protocol=pickle.HIGHEST_PROTOCOL)
965 f.close()
966 if __debugging__ :
967 xbmc.log("Added " + str(stream[0]) + " to stream cache")
968 except:
969 xbmc.log("An error occurred adding to stream")
970
971 def _setSongStream(self, stream):
972 idStream = int(stream[0])
973 stream[1] = self._setDuration(stream[1])
974 streams = self._getStreams()
975 path = os.path.join(cacheDir, 'streams.dmp')
976 i = 0
977
978 for song in streams:
979 if song[0] == idStream:
980 streams[i] = stream
981 try:
982 f = open(path, 'wb')
983 pickle.dump(streams, f, protocol=pickle.HIGHEST_PROTOCOL)
984 f.close()
985 if __debugging__ :
986 xbmc.log("Updated " + str(idStream) + " in stream cache")
987 break;
988 except:
989 xbmc.log("An error occurred setting stream")
990 i = i + 1
991
992 def _getStreams(self):
993 path = os.path.join(cacheDir, 'streams.dmp')
994 try:
995 f = open(path, 'rb')
996 streams = pickle.load(f)
997 f.close()
998 except:
999 streams = []
1000 pass
1001 return streams
1002
1003
1004 # Parse URL parameters
1005 def get_params():
1006 param=[]
1007 paramstring=sys.argv[2]
1008 if __debugging__ :
1009 xbmc.log(paramstring)
1010 if len(paramstring)>=2:
1011 params=sys.argv[2]
1012 cleanedparams=params.replace('?','')
1013 if (params[len(params)-1]=='/'):
1014 params=params[0:len(params)-2]
1015 pairsofparams=cleanedparams.split('&')
1016 param={}
1017 for i in range(len(pairsofparams)):
1018 splitparams={}
1019 splitparams=pairsofparams[i].split('=')
1020 if (len(splitparams))==2:
1021 param[splitparams[0]]=splitparams[1]
1022 return param
1023
1024 # Main
1025 grooveshark = Grooveshark();
1026
1027 params=get_params()
1028 mode=None
1029 try: mode=int(params["mode"])
1030 except: pass
1031 itemId=0
1032 try: itemId=int(params["id"])
1033 except: pass
1034 name = None
1035 try: name=urllib.unquote_plus(params["name"])
1036 except: pass
1037
1038 # Call function for URL
1039 if mode==None:
1040 grooveshark.categories()
1041
1042 elif mode==MODE_SEARCH_SONGS:
1043 grooveshark.searchSongs()
1044
1045 elif mode==MODE_SEARCH_ALBUMS:
1046 grooveshark.searchAlbums()
1047
1048 elif mode==MODE_SEARCH_ARTISTS:
1049 grooveshark.searchArtists()
1050
1051 elif mode==MODE_SEARCH_ARTISTS_ALBUMS:
1052 grooveshark.searchArtistsAlbums(name)
1053
1054 elif mode==MODE_SEARCH_PLAYLISTS:
1055 grooveshark.searchPlaylists()
1056
1057 elif mode==MODE_POPULAR_SONGS:
1058 grooveshark.popularSongs()
1059
1060 elif mode==MODE_ARTIST_POPULAR:
1061 grooveshark.artistPopularSongs()
1062
1063 elif mode==MODE_FAVORITES:
1064 grooveshark.favorites()
1065
1066 elif mode==MODE_PLAYLISTS:
1067 grooveshark.playlists()
1068
1069 elif mode==MODE_SONG_PAGE:
1070 try: offset=urllib.unquote_plus(params["offset"])
1071 except: pass
1072 try: label=urllib.unquote_plus(params["label"])
1073 except: pass
1074 grooveshark.songPage(offset, label, itemId, name)
1075
1076 elif mode==MODE_SONG:
1077 try: album=urllib.unquote_plus(params["album"])
1078 except: pass
1079 try: artist=urllib.unquote_plus(params["artist"])
1080 except: pass
1081 try: coverart=urllib.unquote_plus(params["coverart"])
1082 except: pass
1083 song = grooveshark.songItem(itemId, name, album, artist, coverart)
1084 grooveshark.playSong(song)
1085
1086 elif mode==MODE_ARTIST:
1087 grooveshark.artist(itemId)
1088
1089 elif mode==MODE_ALBUM:
1090 grooveshark.album(itemId)
1091
1092 elif mode==MODE_PLAYLIST:
1093 grooveshark.playlist(itemId, name)
1094
1095 elif mode==MODE_FAVORITE:
1096 grooveshark.favorite(itemId)
1097
1098 elif mode==MODE_UNFAVORITE:
1099 try: prevMode=int(urllib.unquote_plus(params["prevmode"]))
1100 except:
1101 prevMode = 0
1102 grooveshark.unfavorite(itemId, prevMode)
1103
1104 elif mode==MODE_SIMILAR_ARTISTS:
1105 grooveshark.similarArtists(itemId)
1106
1107 elif mode==MODE_MAKE_PLAYLIST:
1108 grooveshark.makePlaylist(itemId, name)
1109
1110 elif mode==MODE_REMOVE_PLAYLIST:
1111 grooveshark.removePlaylist(itemId, name)
1112
1113 elif mode==MODE_RENAME_PLAYLIST:
1114 grooveshark.renamePlaylist(itemId, name)
1115
1116 elif mode==MODE_REMOVE_PLAYLIST_SONG:
1117 try: playlistID=urllib.unquote_plus(params["playlistid"])
1118 except: pass
1119 grooveshark.removePlaylistSong(playlistID, name, itemId)
1120
1121 elif mode==MODE_ADD_PLAYLIST_SONG:
1122 grooveshark.addPlaylistSong(itemId)
1123
1124 if mode < MODE_SONG:
1125 xbmcplugin.endOfDirectory(int(sys.argv[1]))