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