1 # Copyright 2011 Stephen Denham
3 # This file is part of xbmc-groove.
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.
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.
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/>.
19 import urllib, sys, os, shutil, re, pickle, time, tempfile, xbmcaddon, xbmcplugin, xbmcgui, xbmc
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')
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
42 MODE_SIMILAR_ARTISTS = 14
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
57 ACTION_SELECT_ITEM = 7
58 ACTION_PREVIOUS_MENU = 10
60 # Formats for track labels
61 ARTIST_ALBUM_NAME_LABEL = 0
62 NAME_ALBUM_ARTIST_LABEL = 1
64 # Stream marking time (seconds)
65 STREAM_MARKING_TIME = 30
71 player = xbmc.Player()
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)
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)
87 searchArtistsAlbumsName = __language__(30006)
89 thumbDef = os.path.join(imgDir, 'default.tbn')
90 listBackground = os.path.join(imgDir, 'listbackground.png')
92 sys.path.append (libDir)
93 from GroovesharkAPI import GrooveAPI
94 from threading import Event, Thread
96 if __debugging__ == 'true':
102 groovesharkApi = GrooveAPI(__debugging__)
103 if groovesharkApi.pingService() != True:
104 raise StandardError(__language__(30007))
106 dialog = xbmcgui.Dialog(__language__(30008),__language__(30009),__language__(30010))
107 dialog.ok(__language__(30008),__language__(30009))
110 # Mark song as playing or played
111 def markSong(songid, duration, streamKey, streamServerID):
115 if player.isPlayingAudio():
116 tNow = player.getTime()
117 if tNow >= STREAM_MARKING_TIME and songMarkTime == 0:
118 groovesharkApi.markStreamKeyOver30Secs(streamKey, streamServerID)
120 elif duration > tNow and duration - tNow < 2 and songMarkTime >= STREAM_MARKING_TIME:
123 groovesharkApi.markSongComplete(songid, streamKey, streamServerID)
129 def __init__( self, *args, **kwargs ):
130 self.__dict__.update( kwargs )
132 # Window dialog to select a grooveshark playlist
133 class GroovesharkPlaylistSelect(xbmcgui.WindowDialog):
135 def __init__(self, items=[]):
136 gap = int(self.getHeight()/100)
137 w = int(self.getWidth()*0.5)
138 h = self.getHeight()-30*gap
140 rh = self.getHeight()
144 self.imgBg = xbmcgui.ControlImage(x+gap, 5*gap+y, w-2*gap, h-5*gap, listBackground)
145 self.addControl(self.imgBg)
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)
151 self.isSelecting = False
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)
163 # Highlight selected item
164 def setHighlight(self):
168 self.isSelecting = True
170 pos = self.playlistControl.getSelectedPosition()
172 item = self.playlistControl.getListItem(self.lastPos)
174 item = self.playlistControl.getListItem(pos)
177 self.isSelecting = False
180 def onControl(self, control):
181 if control == self.playlistControl:
182 self.selected = self.playlistControl.getSelectedPosition()
185 # Action - close or up/down
186 def onAction(self, action):
187 if action == ACTION_PREVIOUS_MENU:
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)
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
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
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
210 self.finished = Event()
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)
223 def setIterations(self, iterations):
224 self.iterations = iterations
228 return self.iterations * self.interval
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'))
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')
255 def __init__( self ):
256 self._handle = int(sys.argv[1])
257 if os.path.isdir(cacheDir) == False:
258 os.makedirs(cacheDir)
260 xbmc.log(__language__(30012) + " " + cacheDir)
261 artDir = xbmc.translatePath(thumbDir)
262 if os.path.isdir(artDir) == False:
265 xbmc.log(__language__(30012) + " " + artDir)
268 def categories(self):
270 self.userid = self._get_login()
273 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
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)
288 def searchSongs(self):
289 query = self._get_keyboard(default="", heading=__language__(30020))
291 songs = groovesharkApi.getSongSearchResults(query, limit = self.songsearchlimit)
293 self._add_songs_directory(songs)
295 dialog = xbmcgui.Dialog()
296 dialog.ok(__language__(30008), __language__(30021))
302 def searchAlbums(self):
303 query = self._get_keyboard(default="", heading=__language__(30022))
305 albums = groovesharkApi.getAlbumSearchResults(query, limit = self.albumsearchlimit)
306 if (len(albums) > 0):
307 self._add_albums_directory(albums)
309 dialog = xbmcgui.Dialog()
310 dialog.ok(__language__(30008), __language__(30023))
316 def searchArtists(self):
317 query = self._get_keyboard(default="", heading=__language__(30024))
319 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
320 if (len(artists) > 0):
321 self._add_artists_directory(artists)
323 dialog = xbmcgui.Dialog()
324 dialog.ok(__language__(30008), __language__(30025))
329 # Search for playlists
330 def searchPlaylists(self):
331 query = self._get_keyboard(default="", heading=__language__(30026))
333 playlists = groovesharkApi.getUserPlaylistsByUsername(query)
334 if (len(playlists) > 0):
335 self._add_playlists_directory(playlists)
337 dialog = xbmcgui.Dialog()
338 dialog.ok(__language__(30008), __language__(30027))
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))
350 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
351 if (len(artists) > 0):
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)
360 dialog = xbmcgui.Dialog()
361 dialog.ok(__language__(30008), __language__(30029))
364 dialog = xbmcgui.Dialog()
365 dialog.ok(__language__(30008), __language__(30030))
372 userid = self._get_login()
374 favorites = groovesharkApi.getUserFavoriteSongs()
375 if (len(favorites) > 0):
376 self._add_songs_directory(favorites, isFavorites=True)
378 dialog = xbmcgui.Dialog()
379 dialog.ok(__language__(30008), __language__(30031))
383 def popularSongs(self):
384 popular = groovesharkApi.getPopularSongsToday(limit = self.songsearchlimit)
385 if (len(popular) > 0):
386 self._add_songs_directory(popular)
388 dialog = xbmcgui.Dialog()
389 dialog.ok(__language__(30008), __language__(30032))
394 userid = self._get_login()
396 playlists = groovesharkApi.getUserPlaylists()
397 if (len(playlists) > 0):
398 self._add_playlists_directory(playlists)
400 dialog = xbmcgui.Dialog()
401 dialog.ok(__language__(30008), __language__(30033))
404 dialog = xbmcgui.Dialog()
405 dialog.ok(__language__(30008), __language__(30034), __language__(30035))
407 # Make songs a favorite
408 def favorite(self, songid):
409 userid = self._get_login()
412 xbmc.log("Favorite song: " + str(songid))
413 groovesharkApi.addUserFavoriteSong(songID = songid)
414 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30036) + ', 1000, ' + thumbDef + ')')
416 dialog = xbmcgui.Dialog()
417 dialog.ok(__language__(30008), __language__(30034), __language__(30037))
419 # Remove song from favorites
420 def unfavorite(self, songid, prevMode=0):
421 userid = self._get_login()
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 + ")")
431 dialog = xbmcgui.Dialog()
432 dialog.ok(__language__(30008), __language__(30034), __language__(30039))
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)
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)
445 # Show selected playlist
446 def playlist(self, playlistid, playlistname):
447 userid = self._get_login()
449 songs = groovesharkApi.getPlaylistSongs(playlistid)
450 self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL, playlistid=playlistid, playlistname=playlistname)
452 dialog = xbmcgui.Dialog()
453 dialog.ok(__language__(30008), __language__(30034), __language__(30040))
455 # Show popular songs of the artist
456 def artistPopularSongs(self):
457 query = self._get_keyboard(default="", heading=__language__(30041))
459 artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
460 if (len(artists) > 0):
464 xbmc.log("Found " + artist[0] + "...")
465 songs = groovesharkApi.getArtistPopularSongs(artistID, limit = self.songsearchlimit)
467 self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL)
469 dialog = xbmcgui.Dialog()
470 dialog.ok(__language__(30008), __language__(30042))
473 dialog = xbmcgui.Dialog()
474 dialog.ok(__language__(30008), __language__(30043))
480 def playSong(self, item):
485 # Get stream as it could have expired
488 songid = item.getProperty('songid')
489 stream = groovesharkApi.getSubscriberStreamKey(songid)
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)
499 xbmcplugin.setResolvedUrl(handle=int(sys.argv[1]), succeeded=True, listitem=item)
501 xbmc.log("Grooveshark playing: " + url)
502 # Wait for play then start timer
504 while seconds < STREAM_TIMEOUT:
506 if player.isPlayingAudio() == True:
507 if playTimer != None:
510 playTimer = PlayTimer(1, markSong, self._setDuration(duration), [songid, duration, key, server])
515 seconds = seconds + 1
517 xbmc.log("No song URL")
519 xbmc.log("No song stream")
521 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30044) + ', 1000, ' + thumbDef + ')')
523 # Make a song directory item
524 def songItem(self, songid, name, album, artist, coverart, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL):
526 stream = self._getSongStream(songid)
532 songImg = self._get_icon(coverart, 'song-' + str(songid) + "-image")
533 if int(trackLabelFormat) == NAME_ALBUM_ARTIST_LABEL:
534 trackLabel = name + " - " + album + " - " + artist
536 trackLabel = artist + " - " + album + " - " + name
537 item = xbmcgui.ListItem(label = trackLabel, thumbnailImage=songImg, iconImage=songImg)
539 item.setInfo( type="music", infoLabels={ "title": name, "album": album, "artist": artist, "duration": duration} )
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))
552 xbmc.log("No song URL")
556 def songPage(self, offset, trackLabelFormat, playlistid = 0, playlistname = ''):
557 self._add_songs_directory([], trackLabelFormat, offset, playlistid = playlistid, playlistname = playlistname)
559 # Make a playlist from an album
560 def makePlaylist(self, albumid, name):
561 userid = self._get_login()
563 re.split(' - ',name,1)
564 nameTokens = re.split(' - ',name,1) # suggested name
565 name = self._get_keyboard(default=nameTokens[0], heading=__language__(30045))
567 album = groovesharkApi.getAlbumSongs(albumid, limit = self.songsearchlimit)
570 songids.append(song[1])
571 if groovesharkApi.createPlaylist(name, songids) == 0:
572 dialog = xbmcgui.Dialog()
573 dialog.ok(__language__(30008), __language__(30046), name)
575 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30047)+ ', 1000, ' + thumbDef + ')')
577 dialog = xbmcgui.Dialog()
578 dialog.ok(__language__(30008), __language__(30034), __language__(30048))
581 def renamePlaylist(self, playlistid, name):
582 userid = self._get_login()
584 newname = self._get_keyboard(default=name, heading=__language__(30049))
587 elif groovesharkApi.playlistRename(playlistid, newname) == 0:
588 dialog = xbmcgui.Dialog()
589 dialog.ok(__language__(30008), __language__(30050), name)
591 # Refresh to show new item name
592 xbmc.executebuiltin("Container.Refresh")
594 dialog = xbmcgui.Dialog()
595 dialog.ok(__language__(30008), __language__(30034), __language__(30051))
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()
603 if groovesharkApi.playlistDelete(playlistid) == 0:
604 dialog = xbmcgui.Dialog()
605 dialog.ok(__language__(30008), __language__(30053), name)
607 # Refresh to remove item from directory
608 xbmc.executebuiltin("Container.Refresh(" + playlistsUrl + ")")
610 dialog = xbmcgui.Dialog()
611 dialog.ok(__language__(30008), __language__(30034), __language__(30054))
613 # Add song to playlist
614 def addPlaylistSong(self, songid):
615 userid = self._get_login()
617 playlists = groovesharkApi.getUserPlaylists()
618 if (len(playlists) > 0):
620 # Select the playlist
621 playlistSelect = GroovesharkPlaylistSelect(items=playlists)
622 playlistSelect.setFocus(playlistSelect.playlistControl)
623 playlistSelect.doModal()
624 i = playlistSelect.selected
628 if i >= len(playlists):
629 name = self._get_keyboard(default='', heading=__language__(30055))
632 songIds.append(songid)
633 if groovesharkApi.createPlaylist(name, songIds) == 0:
634 dialog = xbmcgui.Dialog()
635 dialog.ok(__language__(30008), __language__(30056), name)
637 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30057) + ', 1000, ' + thumbDef + ')')
640 playlist = playlists[i]
641 playlistid = playlist[1]
643 xbmc.log("Add song " + str(songid) + " to playlist " + str(playlistid))
645 songs = groovesharkApi.getPlaylistSongs(playlistid)
647 songIDs.append(song[1])
648 songIDs.append(songid)
649 ret = groovesharkApi.setPlaylistSongs(playlistid, songIDs)
651 dialog = xbmcgui.Dialog()
652 dialog.ok(__language__(30008), __language__(30058))
654 xbmc.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30059) + ', 1000, ' + thumbDef + ')')
656 dialog = xbmcgui.Dialog()
657 dialog.ok(__language__(30008), __language__(30060))
660 dialog = xbmcgui.Dialog()
661 dialog.ok(__language__(30008), __language__(30034), __language__(30061))
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()
669 songs = groovesharkApi.getPlaylistSongs(playlistID)
672 if (song[1] != songid):
673 songIDs.append(song[1])
674 ret = groovesharkApi.setPlaylistSongs(playlistID, songIDs)
676 dialog = xbmcgui.Dialog()
677 dialog.ok(__language__(30008), __language__(30064), __language__(30065))
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=" + playlistname + ")")
683 dialog = xbmcgui.Dialog()
684 dialog.ok(__language__(30008), __language__(30034), __language__(30067))
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)
692 dialog = xbmcgui.Dialog()
693 dialog.ok(__language__(30008), __language__(30068))
697 def _get_keyboard(self, default="", heading="", hidden=False):
698 kb = xbmc.Keyboard(default, heading, hidden)
700 if (kb.isConfirmed()):
701 return unicode(kb.getText(), "utf-8")
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))
712 uid = groovesharkApi.login(self.username, self.password)
716 dialog = xbmcgui.Dialog()
717 dialog.ok(__language__(30008), __language__(30069), __language__(30070))
721 def _get_icon(self, url, songid):
723 localThumb = os.path.join(xbmc.translatePath(os.path.join(thumbDir, str(songid)))) + '.tbn'
725 if os.path.isfile(localThumb) == False:
726 loc = urllib.URLopener()
727 loc.retrieve(url, localThumb)
729 shutil.copy2(thumbDef, localThumb)
730 return os.path.join(os.path.join(thumbDir, str(songid))) + '.tbn'
734 # Add songs to directory
735 def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, offset=0, playlistid=0, playlistname='', isFavorites=False):
737 totalSongs = len(songs)
743 if offset == 0 and totalSongs <= self.songspagelimit:
745 xbmc.log("Found " + str(totalSongs) + " songs...")
748 # Cache all next pages songs
750 self._setSavedSongs(songs)
752 songs = self._getSavedSongs()
753 totalSongs = len(songs)
757 end = min(start + self.songspagelimit,totalSongs)
769 item = self.songItem(songid, name, album, artist, coverart, trackLabelFormat)
771 coverart = item.getProperty('coverart')
775 u=sys.argv[0]+"?mode="+str(MODE_SONG)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid) \
776 +"&album="+urllib.quote_plus(songalbum) \
777 +"&artist="+urllib.quote_plus(songartist) \
778 +"&coverart="+urllib.quote_plus(coverart)
779 fav=sys.argv[0]+"?mode="+str(MODE_FAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
780 unfav=sys.argv[0]+"?mode="+str(MODE_UNFAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)+"&prevmode="
782 if isFavorites == True:
783 unfav = unfav +str(MODE_FAVORITES)
785 menuItems.append((__language__(30071), "XBMC.RunPlugin("+fav+")"))
786 menuItems.append((__language__(30072), "XBMC.RunPlugin("+unfav+")"))
788 rmplaylstsong=sys.argv[0]+"?playlistid="+str(playlistid)+"&id="+str(songid)+"&mode="+str(MODE_REMOVE_PLAYLIST_SONG)+"&name="+playlistname
789 menuItems.append((__language__(30073), "XBMC.RunPlugin("+rmplaylstsong+")"))
791 addplaylstsong=sys.argv[0]+"?id="+str(songid)+"&mode="+str(MODE_ADD_PLAYLIST_SONG)
792 menuItems.append((__language__(30074), "XBMC.RunPlugin("+addplaylstsong+")"))
793 item.addContextMenuItems(menuItems, replaceItems=False)
794 xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False, totalItems=items)
797 end = min(end + 1,totalSongs)
799 xbmc.log(song[0] + " does not exist.")
803 u=sys.argv[0]+"?mode="+str(MODE_SONG_PAGE)+"&id=playlistid"+"&offset="+str(end)+"&label="+str(trackLabelFormat)+"&name="+playlistname
804 self._add_dir(__language__(30075) + '...', u, MODE_SONG_PAGE, self.songImg, 0, totalSongs - end)
806 xbmcplugin.setContent(self._handle, 'songs')
807 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
809 # Add albums to directory
810 def _add_albums_directory(self, albums, artistid=0, isverified=False):
814 xbmc.log("Found " + str(n) + " albums...")
819 if isverified or groovesharkApi.getDoesAlbumExist(albumID):
820 albumArtistName = album[0]
822 albumImage = self._get_icon(album[4], 'album-' + str(albumID))
823 self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID, itemsExisting)
825 itemsExisting = itemsExisting - 1
827 # Not supported by key
829 # self._add_dir('Similar artists...', '', MODE_SIMILAR_ARTISTS, self.artistImg, artistid)
830 xbmcplugin.setContent(self._handle, 'albums')
831 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE)
832 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
834 # Add artists to directory
835 def _add_artists_directory(self, artists):
839 xbmc.log("Found " + str(n) + " artists...")
844 if groovesharkApi.getDoesArtistExist(artistID):
845 artistName = artist[0]
846 self._add_dir(artistName, '', MODE_ARTIST, self.artistImg, artistID, itemsExisting)
848 itemsExisting = itemsExisting - 1
850 xbmcplugin.setContent(self._handle, 'artists')
851 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ARTIST_IGNORE_THE)
852 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
854 # Add playlists to directory
855 def _add_playlists_directory(self, playlists):
858 xbmc.log("Found " + str(n) + " playlists...")
861 playlist = playlists[i]
862 playlistName = playlist[0]
863 playlistID = playlist[1]
864 dir = self._add_dir(playlistName, '', MODE_PLAYLIST, self.playlistImg, playlistID, n)
866 xbmcplugin.setContent(self._handle, 'files')
867 xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_LABEL)
868 xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
870 # Add whatever directory
871 def _add_dir(self, name, url, mode, iconimage, id, items=1):
874 u=sys.argv[0]+"?mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
877 dir=xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
878 dir.setInfo( type="Music", infoLabels={ "title": name } )
882 if mode == MODE_ALBUM:
883 mkplaylst=sys.argv[0]+"?mode="+str(MODE_MAKE_PLAYLIST)+"&name="+name+"&id="+str(id)
884 menuItems.append((__language__(30076), "XBMC.RunPlugin("+mkplaylst+")"))
885 if mode == MODE_PLAYLIST:
886 rmplaylst=sys.argv[0]+"?mode="+str(MODE_REMOVE_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
887 menuItems.append((__language__(30077), "XBMC.RunPlugin("+rmplaylst+")"))
888 mvplaylst=sys.argv[0]+"?mode="+str(MODE_RENAME_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
889 menuItems.append((__language__(30078), "XBMC.RunPlugin("+mvplaylst+")"))
891 dir.addContextMenuItems(menuItems, replaceItems=False)
893 return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=dir,isFolder=True, totalItems=items)
895 def _getSavedSongs(self):
896 path = os.path.join(cacheDir, 'songs.dmp')
899 songs = pickle.load(f)
906 def _setSavedSongs(self, songs):
908 # Create the 'data' directory if it doesn't exist.
909 if not os.path.exists(cacheDir):
910 os.makedirs(cacheDir)
911 path = os.path.join(cacheDir, 'songs.dmp')
913 pickle.dump(songs, f, protocol=pickle.HIGHEST_PROTOCOL)
916 xbmc.log("An error occurred saving songs")
919 # Duration to seconds
920 def _setDuration(self, usecs):
922 usecs = usecs * 10 # Some durations are 10x to small
923 return int(usecs / 1000000)
925 def _getSongStream(self, songid):
929 path = os.path.join(cacheDir, 'streams.dmp')
932 streams = pickle.load(f)
939 stream = [id, duration, url, key, server]
941 xbmc.log("Found " + str(id) + " in cache")
949 stream = groovesharkApi.getSubscriberStreamKey(songid)
950 if stream != False and stream['url'] != '':
951 duration = self._setDuration(stream['uSecs'])
953 key = stream['StreamKey']
954 server = stream['StreamServerID']
955 stream = [id, duration, url, key, server]
956 self._addSongStream(stream, streams)
960 def _addSongStream(self, stream, streams):
962 streams.append(stream)
963 # Create the cache directory if it doesn't exist.
964 if not os.path.exists(cacheDir):
965 os.makedirs(cacheDir)
966 path = os.path.join(cacheDir, 'streams.dmp')
968 pickle.dump(streams, f, protocol=pickle.HIGHEST_PROTOCOL)
971 xbmc.log("An error occurred adding stream")
974 def _setSongStream(self, stream):
976 stream[1] = self._setDuration(stream[1])
978 path = os.path.join(cacheDir, 'streams.dmp')
981 streams = pickle.load(f)
987 xbmc.log("Added " + str(id) + " to cache")
988 pickle.dump(streams, f, protocol=pickle.HIGHEST_PROTOCOL)
993 xbmc.log("An error occurred setting stream")
996 # Parse URL parameters
999 paramstring=sys.argv[2]
1001 xbmc.log(paramstring)
1002 if len(paramstring)>=2:
1004 cleanedparams=params.replace('?','')
1005 if (params[len(params)-1]=='/'):
1006 params=params[0:len(params)-2]
1007 pairsofparams=cleanedparams.split('&')
1009 for i in range(len(pairsofparams)):
1011 splitparams=pairsofparams[i].split('=')
1012 if (len(splitparams))==2:
1013 param[splitparams[0]]=splitparams[1]
1017 grooveshark = Grooveshark();
1021 try: mode=int(params["mode"])
1024 try: id=int(params["id"])
1027 try: name=urllib.unquote_plus(params["name"])
1030 # Call function for URL
1032 grooveshark.categories()
1034 elif mode==MODE_SEARCH_SONGS:
1035 grooveshark.searchSongs()
1037 elif mode==MODE_SEARCH_ALBUMS:
1038 grooveshark.searchAlbums()
1040 elif mode==MODE_SEARCH_ARTISTS:
1041 grooveshark.searchArtists()
1043 elif mode==MODE_SEARCH_ARTISTS_ALBUMS:
1044 grooveshark.searchArtistsAlbums(name)
1046 elif mode==MODE_SEARCH_PLAYLISTS:
1047 grooveshark.searchPlaylists()
1049 elif mode==MODE_POPULAR_SONGS:
1050 grooveshark.popularSongs()
1052 elif mode==MODE_ARTIST_POPULAR:
1053 grooveshark.artistPopularSongs()
1055 elif mode==MODE_FAVORITES:
1056 grooveshark.favorites()
1058 elif mode==MODE_PLAYLISTS:
1059 grooveshark.playlists()
1061 elif mode==MODE_SONG_PAGE:
1062 try: offset=urllib.unquote_plus(params["offset"])
1064 try: label=urllib.unquote_plus(params["label"])
1066 grooveshark.songPage(offset, label, id, name)
1068 elif mode==MODE_SONG:
1069 try: album=urllib.unquote_plus(params["album"])
1071 try: artist=urllib.unquote_plus(params["artist"])
1073 try: coverart=urllib.unquote_plus(params["coverart"])
1075 song = grooveshark.songItem(id, name, album, artist, coverart)
1076 grooveshark.playSong(song)
1078 elif mode==MODE_ARTIST:
1079 grooveshark.artist(id)
1081 elif mode==MODE_ALBUM:
1082 grooveshark.album(id)
1084 elif mode==MODE_PLAYLIST:
1085 grooveshark.playlist(id, name)
1087 elif mode==MODE_FAVORITE:
1088 grooveshark.favorite(id)
1090 elif mode==MODE_UNFAVORITE:
1091 try: prevMode=int(urllib.unquote_plus(params["prevmode"]))
1094 grooveshark.unfavorite(id, prevMode)
1096 elif mode==MODE_SIMILAR_ARTISTS:
1097 grooveshark.similarArtists(id)
1099 elif mode==MODE_MAKE_PLAYLIST:
1100 grooveshark.makePlaylist(id, name)
1102 elif mode==MODE_REMOVE_PLAYLIST:
1103 grooveshark.removePlaylist(id, name)
1105 elif mode==MODE_RENAME_PLAYLIST:
1106 grooveshark.renamePlaylist(id, name)
1108 elif mode==MODE_REMOVE_PLAYLIST_SONG:
1109 try: playlistID=urllib.unquote_plus(params["playlistid"])
1111 grooveshark.removePlaylistSong(playlistID, name, id)
1113 elif mode==MODE_ADD_PLAYLIST_SONG:
1114 grooveshark.addPlaylistSong(id)
1116 if mode < MODE_SONG:
1117 xbmcplugin.endOfDirectory(int(sys.argv[1]))