1 import urllib
, sys
, os
, shutil
, re
, pickle
, time
, tempfile
, xbmcaddon
, xbmcplugin
, xbmcgui
, xbmc
4 MODE_SEARCH_ARTISTS
= 3
5 MODE_SEARCH_ARTISTS_ALBUMS
= 4
6 MODE_SEARCH_PLAYLISTS
= 5
7 MODE_ARTIST_POPULAR
= 6
15 MODE_SIMILAR_ARTISTS
= 14
19 MODE_MAKE_PLAYLIST
= 18
20 MODE_REMOVE_PLAYLIST
= 19
21 MODE_RENAME_PLAYLIST
= 20
22 MODE_REMOVE_PLAYLIST_SONG
= 21
23 MODE_ADD_PLAYLIST_SONG
= 22
30 ACTION_SELECT_ITEM
= 7
31 ACTION_PREVIOUS_MENU
= 10
33 # Formats for track labels
34 ARTIST_ALBUM_NAME_LABEL
= 0
35 NAME_ALBUM_ARTIST_LABEL
= 1
37 # Stream marking time (seconds)
38 STREAM_MARKING_TIME
= 30
41 player
= xbmc
.Player()
45 resDir
= xbmc
.translatePath(os
.path
.join(baseDir
, 'resources'))
46 libDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'lib'))
47 imgDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'img'))
48 cacheDir
= os
.path
.join(xbmc
.translatePath('special://masterprofile/addon_data/'), os
.path
.basename(os
.getcwd()))
49 thumbDirName
= 'thumb'
50 thumbDir
= os
.path
.join('special://masterprofile/addon_data/', os
.path
.basename(os
.getcwd()), thumbDirName
)
52 baseModeUrl
= 'plugin://plugin.audio.groove/'
53 playlistUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLIST
)
54 playlistsUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLISTS
)
55 favoritesUrl
= baseModeUrl
+ '?mode=' + str(MODE_FAVORITES
)
57 searchArtistsAlbumsName
= "Search for artist's albums..."
59 thumbDef
= os
.path
.join(imgDir
, 'default.tbn')
60 listBackground
= os
.path
.join(imgDir
, 'listbackground.png')
62 sys
.path
.append (libDir
)
63 from GroovesharkAPI
import GrooveAPI
64 from threading
import Event
, Thread
67 groovesharkApi
= GrooveAPI()
68 if groovesharkApi
.pingService() != True:
69 raise StandardError('No Grooveshark service')
71 dialog
= xbmcgui
.Dialog()
72 dialog
.ok('Grooveshark XBMC', 'Unable to connect with Grooveshark.', 'Please try again later')
75 # Mark song as playing or played
76 def markSong(songid
, duration
):
80 if player
.isPlayingAudio():
81 tNow
= player
.getTime()
82 if tNow
>= STREAM_MARKING_TIME
and songMarkTime
== 0:
83 groovesharkApi
.markStreamKeyOver30Secs()
85 elif duration
> tNow
and duration
- tNow
< 2 and songMarkTime
>= STREAM_MARKING_TIME
:
88 groovesharkApi
.markSongComplete(songid
)
94 def __init__( self
, *args
, **kwargs
):
95 self
.__dict
__.update( kwargs
)
97 # Window dialog to select a grooveshark playlist
98 class GroovesharkPlaylistSelect(xbmcgui
.WindowDialog
):
100 def __init__(self
, items
=[]):
101 gap
= int(self
.getHeight()/100)
102 w
= int(self
.getWidth()*0.5)
103 h
= self
.getHeight()-30*gap
105 rh
= self
.getHeight()
109 self
.imgBg
= xbmcgui
.ControlImage(x
+gap
, 5*gap
+y
, w
-2*gap
, h
-5*gap
, listBackground
)
110 self
.addControl(self
.imgBg
)
112 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)
113 self
.addControl(self
.playlistControl
)
116 self
.isSelecting
= False
119 for playlist
in items
:
120 listitems
.append(xbmcgui
.ListItem(playlist
[0]))
121 listitems
.append(xbmcgui
.ListItem('New...'))
122 self
.playlistControl
.addItems(listitems
)
123 self
.setFocus(self
.playlistControl
)
124 self
.playlistControl
.selectItem(0)
125 item
= self
.playlistControl
.getListItem(self
.lastPos
)
128 # Highlight selected item
129 def setHighlight(self
):
133 self
.isSelecting
= True
135 pos
= self
.playlistControl
.getSelectedPosition()
137 item
= self
.playlistControl
.getListItem(self
.lastPos
)
139 item
= self
.playlistControl
.getListItem(pos
)
142 self
.isSelecting
= False
145 def onControl(self
, control
):
146 if control
== self
.playlistControl
:
147 self
.selected
= self
.playlistControl
.getSelectedPosition()
150 # Action - close or up/down
151 def onAction(self
, action
):
152 if action
== ACTION_PREVIOUS_MENU
:
155 elif action
== ACTION_MOVE_UP
or action
== ACTION_MOVE_DOWN
or action
== ACTION_PAGE_UP
or action
== ACTION_PAGE_DOWN
== 6:
156 self
.setFocus(self
.playlistControl
)
160 class PlayTimer(Thread
):
161 # interval -- floating point number specifying the number of seconds to wait before executing function
162 # function -- the function (or callable object) to be executed
164 # iterations -- integer specifying the number of iterations to perform
165 # args -- list of positional arguments passed to function
166 # kwargs -- dictionary of keyword arguments passed to function
168 def __init__(self
, interval
, function
, iterations
=0, args
=[], kwargs
={}):
169 Thread
.__init
__(self
)
170 self
.interval
= interval
171 self
.function
= function
172 self
.iterations
= iterations
175 self
.finished
= Event()
179 while not self
.finished
.isSet() and (self
.iterations
<= 0 or count
< self
.iterations
):
180 self
.finished
.wait(self
.interval
)
181 if not self
.finished
.isSet():
182 self
.function(*self
.args
, **self
.kwargs
)
188 def setIterations(self
, iterations
):
189 self
.iterations
= iterations
193 return self
.iterations
* self
.interval
198 albumImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'album.png'))
199 artistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artist.png'))
200 artistsAlbumsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artistsalbums.png'))
201 favoritesImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'favorites.png'))
202 playlistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'playlist.png'))
203 usersplaylistsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'usersplaylists.png'))
204 popularSongsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongs.png'))
205 popularSongsArtistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongsArtist.png'))
206 songImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'song.png'))
207 defImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'default.tbn'))
208 fanImg
= xbmc
.translatePath(os
.path
.join(baseDir
, 'fanart.png'))
210 settings
= xbmcaddon
.Addon(id='plugin.audio.groove')
211 songsearchlimit
= int(settings
.getSetting('songsearchlimit'))
212 albumsearchlimit
= int(settings
.getSetting('albumsearchlimit'))
213 artistsearchlimit
= int(settings
.getSetting('artistsearchlimit'))
214 songspagelimit
= int(settings
.getSetting('songspagelimit'))
215 username
= settings
.getSetting('username')
216 password
= settings
.getSetting('password')
219 def __init__( self
):
220 self
._handle
= int(sys
.argv
[1])
221 if os
.path
.isdir(cacheDir
) == False:
222 os
.makedirs(cacheDir
)
223 xbmc
.log("Made " + cacheDir
)
224 artDir
= xbmc
.translatePath(thumbDir
)
225 if os
.path
.isdir(artDir
) == False:
227 xbmc
.log("Made " + artDir
)
230 def categories(self
):
232 self
.userid
= self
._get
_login
()
235 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
237 self
._add
_dir
('Search for songs...', '', MODE_SEARCH_SONGS
, self
.songImg
, 0)
238 self
._add
_dir
('Search for albums...', '', MODE_SEARCH_ALBUMS
, self
.albumImg
, 0)
239 self
._add
_dir
('Search for artists...', '', MODE_SEARCH_ARTISTS
, self
.artistImg
, 0)
240 self
._add
_dir
(searchArtistsAlbumsName
, '', MODE_SEARCH_ARTISTS_ALBUMS
, self
.artistsAlbumsImg
, 0)
241 # Not supported by key
242 #self._add_dir("Search for user's playlists...", '', MODE_SEARCH_PLAYLISTS, self.usersplaylistsImg, 0)
243 self
._add
_dir
('Popular Grooveshark songs for artist...', '', MODE_ARTIST_POPULAR
, self
.popularSongsArtistImg
, 0)
244 self
._add
_dir
('Popular Grooveshark songs', '', MODE_POPULAR_SONGS
, self
.popularSongsImg
, 0)
245 if (self
.userid
!= 0):
246 self
._add
_dir
('My Grooveshark favorites', '', MODE_FAVORITES
, self
.favoritesImg
, 0)
247 self
._add
_dir
('My Grooveshark playlists', '', MODE_PLAYLISTS
, self
.playlistImg
, 0)
250 def searchSongs(self
):
251 query
= self
._get
_keyboard
(default
="", heading
='Search for songs powered by Grooveshark')
253 songs
= groovesharkApi
.getSongSearchResults(query
, limit
= self
.songsearchlimit
)
255 self
._add
_songs
_directory
(songs
)
257 dialog
= xbmcgui
.Dialog()
258 dialog
.ok('Grooveshark XBMC', 'No matching songs.')
264 def searchAlbums(self
):
265 query
= self
._get
_keyboard
(default
="", heading
='Search for albums powered by Grooveshark')
267 albums
= groovesharkApi
.getAlbumSearchResults(query
, limit
= self
.albumsearchlimit
)
268 if (len(albums
) > 0):
269 self
._add
_albums
_directory
(albums
)
271 dialog
= xbmcgui
.Dialog()
272 dialog
.ok('Grooveshark XBMC', 'No matching albums.')
278 def searchArtists(self
):
279 query
= self
._get
_keyboard
(default
="", heading
='Search for artists powered by Grooveshark')
281 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
282 if (len(artists
) > 0):
283 self
._add
_artists
_directory
(artists
)
285 dialog
= xbmcgui
.Dialog()
286 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
291 # Search for playlists
292 def searchPlaylists(self
):
293 query
= self
._get
_keyboard
(default
="", heading
="Username")
295 playlists
= groovesharkApi
.getUserPlaylistsByUsername(query
)
296 if (len(playlists
) > 0):
297 self
._add
_playlists
_directory
(playlists
)
299 dialog
= xbmcgui
.Dialog()
300 dialog
.ok('Grooveshark XBMC', 'No Grooveshark playlists found.')
305 # Search for artists albums
306 def searchArtistsAlbums(self
, artistName
= None):
307 if artistName
== None or artistName
== searchArtistsAlbumsName
:
308 query
= self
._get
_keyboard
(default
="", heading
="Search for artist's albums powered by Grooveshark")
312 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
313 if (len(artists
) > 0):
316 xbmc
.log("Found " + artist
[0] + "...")
317 albums
= groovesharkApi
.getArtistAlbums(artistID
, limit
= self
.albumsearchlimit
)
318 if (len(albums
) > 0):
319 self
._add
_albums
_directory
(albums
, artistID
)
321 dialog
= xbmcgui
.Dialog()
322 dialog
.ok('Grooveshark XBMC', 'No matching albums.')
325 dialog
= xbmcgui
.Dialog()
326 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
333 userid
= self
._get
_login
()
335 favorites
= groovesharkApi
.getUserFavoriteSongs()
336 if (len(favorites
) > 0):
337 self
._add
_songs
_directory
(favorites
, isFavorites
=True)
339 dialog
= xbmcgui
.Dialog()
340 dialog
.ok('Grooveshark XBMC', 'You have no favorites.')
344 def popularSongs(self
):
345 popular
= groovesharkApi
.getPopularSongsToday(limit
= self
.songsearchlimit
)
346 if (len(popular
) > 0):
347 self
._add
_songs
_directory
(popular
)
349 dialog
= xbmcgui
.Dialog()
350 dialog
.ok('Grooveshark XBMC', 'No popular songs.')
355 userid
= self
._get
_login
()
357 playlists
= groovesharkApi
.getUserPlaylists()
358 if (len(playlists
) > 0):
359 self
._add
_playlists
_directory
(playlists
)
361 dialog
= xbmcgui
.Dialog()
362 dialog
.ok('Grooveshark XBMC', 'You have no Grooveshark playlists.')
365 dialog
= xbmcgui
.Dialog()
366 dialog
.ok('Grooveshark XBMC', 'You must be logged in ', ' to see your Grooveshark playlists.')
368 # Make songs a favorite
369 def favorite(self
, songid
):
370 userid
= self
._get
_login
()
372 xbmc
.log("Favorite song: " + str(songid
))
373 groovesharkApi
.addUserFavoriteSong(songID
= songid
)
374 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Added to favorites, 1000, ' + thumbDef
+ ')')
376 dialog
= xbmcgui
.Dialog()
377 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to add favorites.')
379 # Remove song from favorites
380 def unfavorite(self
, songid
, prevMode
=0):
381 userid
= self
._get
_login
()
383 xbmc
.log("Unfavorite song: " + str(songid
) + ', previous mode was ' + str(prevMode
))
384 groovesharkApi
.removeUserFavoriteSongs(songIDs
= songid
)
385 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Removed from Grooveshark favorites, 1000, ' + thumbDef
+ ')')
386 # Refresh to remove item from directory
387 if (int(prevMode
) == MODE_FAVORITES
):
388 xbmc
.executebuiltin("Container.Refresh(" + favoritesUrl
+ ")")
390 dialog
= xbmcgui
.Dialog()
391 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to remove Grooveshark favorites.')
394 # Show selected album
395 def album(self
, albumid
):
396 album
= groovesharkApi
.getAlbumSongs(albumid
, limit
= self
.songsearchlimit
)
397 self
._add
_songs
_directory
(album
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
399 # Show selected artist
400 def artist(self
, artistid
):
401 albums
= groovesharkApi
.getArtistAlbums(artistid
, limit
= self
.albumsearchlimit
)
402 self
._add
_albums
_directory
(albums
, artistid
)
404 # Show selected playlist
405 def playlist(self
, playlistid
, playlistname
):
406 userid
= self
._get
_login
()
408 songs
= groovesharkApi
.getPlaylistSongs(playlistid
)
409 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
, playlistid
=playlistid
, playlistname
=playlistname
)
411 dialog
= xbmcgui
.Dialog()
412 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to get Grooveshark playlists.')
414 # Show popular songs of the artist
415 def artistPopularSongs(self
):
416 query
= self
._get
_keyboard
(default
="", heading
="Artist")
418 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
419 if (len(artists
) > 0):
422 xbmc
.log("Found " + artist
[0] + "...")
423 songs
= groovesharkApi
.getArtistPopularSongs(artistID
, limit
= self
.songsearchlimit
)
425 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
427 dialog
= xbmcgui
.Dialog()
428 dialog
.ok('Grooveshark XBMC', 'No popular songs.')
431 dialog
= xbmcgui
.Dialog()
432 dialog
.ok('Grooveshark XBMC', 'No matching artists.')
438 def playSong(self
, item
):
442 songid
= item
.getProperty('songid')
443 stream
= groovesharkApi
.getSubscriberStreamKey(songid
)
446 xbmc
.log("Grooveshark playing: " + url
)
447 xbmcplugin
.setResolvedUrl(handle
=int(sys
.argv
[1]), succeeded
=True, listitem
=item
)
448 # Wait for play then start time
450 while seconds
< STREAM_MARKING_TIME
:
452 if player
.isPlayingAudio() == True:
453 if playTimer
!= None:
456 duration
= int(item
.getProperty('duration'))
457 playTimer
= PlayTimer(1, markSong
, duration
, [songid
, duration
])
462 seconds
= seconds
+ 1
464 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Unable to play song, 1000, ' + thumbDef
+ ')')
466 # Make a song directory item
467 def songItem(self
, songid
, name
, album
, artist
, coverart
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
):
468 songImg
= self
._get
_icon
(coverart
, 'song-' + str(songid
) + "-image")
469 if int(trackLabelFormat
) == NAME_ALBUM_ARTIST_LABEL
:
470 trackLabel
= name
+ " - " + album
+ " - " + artist
472 trackLabel
= artist
+ " - " + album
+ " - " + name
473 duration
= self
._getSongDuration
(songid
)
474 item
= xbmcgui
.ListItem(label
= trackLabel
, thumbnailImage
=songImg
, iconImage
=songImg
)
475 item
.setInfo( type="music", infoLabels
={ "title": name
, "album": album
, "artist": artist
, "duration": duration
} )
476 item
.setProperty('mimetype', 'audio/mpeg')
477 item
.setProperty("IsPlayable", "true")
478 item
.setProperty('songid', str(songid
))
479 item
.setProperty('coverart', songImg
)
480 item
.setProperty('title', name
)
481 item
.setProperty('album', album
)
482 item
.setProperty('artist', artist
)
483 item
.setProperty('duration', str(duration
))
488 def songPage(self
, page
, trackLabelFormat
, playlistid
= 0, playlistname
= ''):
489 self
._add
_songs
_directory
([], trackLabelFormat
, page
, playlistid
= playlistid
, playlistname
= playlistname
)
491 # Make a playlist from an album
492 def makePlaylist(self
, albumid
, name
):
493 userid
= self
._get
_login
()
495 re
.split(' - ',name
,1)
496 nameTokens
= re
.split(' - ',name
,1) # suggested name
497 name
= self
._get
_keyboard
(default
=nameTokens
[0], heading
="Grooveshark playlist name")
499 album
= groovesharkApi
.getAlbumSongs(albumid
, limit
= self
.songsearchlimit
)
502 songids
.append(song
[1])
503 if groovesharkApi
.createPlaylist(name
, songids
) == 0:
504 dialog
= xbmcgui
.Dialog()
505 dialog
.ok('Grooveshark XBMC', 'Cannot create Grooveshark playlist ', name
)
507 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Grooveshark playlist created, 1000, ' + thumbDef
+ ')')
509 dialog
= xbmcgui
.Dialog()
510 dialog
.ok('Grooveshark XBMC', 'You must be logged in ', ' to create a Grooveshark playlist.')
513 def renamePlaylist(self
, playlistid
, name
):
514 userid
= self
._get
_login
()
516 newname
= self
._get
_keyboard
(default
=name
, heading
="Grooveshark playlist name")
519 elif groovesharkApi
.playlistRename(playlistid
, newname
) == 0:
520 dialog
= xbmcgui
.Dialog()
521 dialog
.ok('Grooveshark XBMC', 'Cannot rename Grooveshark playlist ', name
)
523 # Refresh to show new item name
524 xbmc
.executebuiltin("Container.Refresh")
526 dialog
= xbmcgui
.Dialog()
527 dialog
.ok('Grooveshark XBMC', 'You must be logged in ', ' to rename a Grooveshark playlist.')
530 def removePlaylist(self
, playlistid
, name
):
531 dialog
= xbmcgui
.Dialog()
532 if dialog
.yesno('Grooveshark XBMC', name
, 'Delete this Grooveshark playlist?') == True:
533 userid
= self
._get
_login
()
535 if groovesharkApi
.playlistDelete(playlistid
) == 0:
536 dialog
= xbmcgui
.Dialog()
537 dialog
.ok('Grooveshark XBMC', 'Cannot remove Grooveshark playlist ', name
)
539 # Refresh to remove item from directory
540 xbmc
.executebuiltin("Container.Refresh(" + playlistsUrl
+ ")")
542 dialog
= xbmcgui
.Dialog()
543 dialog
.ok('Grooveshark XBMC', 'You must be logged in ', ' to delete a Grooveshark playlist.')
545 # Add song to playlist
546 def addPlaylistSong(self
, songid
):
547 userid
= self
._get
_login
()
549 playlists
= groovesharkApi
.getUserPlaylists()
550 if (len(playlists
) > 0):
552 # Select the playlist
553 playlistSelect
= GroovesharkPlaylistSelect(items
=playlists
)
554 playlistSelect
.setFocus(playlistSelect
.playlistControl
)
555 playlistSelect
.doModal()
556 i
= playlistSelect
.selected
560 if i
>= len(playlists
):
561 name
= self
._get
_keyboard
(default
='', heading
="Grooveshark playlist name")
564 songIds
.append(songid
)
565 if groovesharkApi
.createPlaylist(name
, songIds
) == 0:
566 dialog
= xbmcgui
.Dialog()
567 dialog
.ok('Grooveshark XBMC', 'Cannot create Grooveshark playlist ', name
)
569 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Grooveshark playlist created, 1000, ' + thumbDef
+ ')')
572 playlist
= playlists
[i
]
573 playlistid
= playlist
[1]
574 xbmc
.log("Add song " + str(songid
) + " to playlist " + str(playlistid
))
576 songs
= groovesharkApi
.getPlaylistSongs(playlistid
)
578 songIDs
.append(song
[1])
579 songIDs
.append(songid
)
580 ret
= groovesharkApi
.setPlaylistSongs(playlistid
, songIDs
)
582 dialog
= xbmcgui
.Dialog()
583 dialog
.ok('Grooveshark XBMC', 'Cannot add to playlist ')
585 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Added song to Grooveshark playlist, 1000, ' + thumbDef
+ ')')
587 dialog
= xbmcgui
.Dialog()
588 dialog
.ok('Grooveshark XBMC', 'You have no Grooveshark playlists.')
591 dialog
= xbmcgui
.Dialog()
592 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to add a song to a Grooveshark playlist.')
594 # Remove song from playlist
595 def removePlaylistSong(self
, playlistid
, playlistname
, songid
):
596 dialog
= xbmcgui
.Dialog()
597 if dialog
.yesno('Grooveshark XBMC', 'Delete this song from', 'the Grooveshark playlist?') == True:
598 userid
= self
._get
_login
()
600 songs
= groovesharkApi
.getPlaylistSongs(playlistID
)
603 if (song
[1] != songid
):
604 songIDs
.append(song
[1])
605 ret
= groovesharkApi
.setPlaylistSongs(playlistID
, songIDs
)
607 dialog
= xbmcgui
.Dialog()
608 dialog
.ok('Grooveshark XBMC', 'Failed to remove', 'song from Grooveshark playlist.')
610 # Refresh to remove item from directory
611 xbmc
.executebuiltin('XBMC.Notification(Grooveshark XBMC, Removed song from Grooveshark playlist, 1000, ' + thumbDef
+ ')')
612 xbmc
.executebuiltin("Container.Update(" + playlistUrl
+ "&id="+str(playlistid
) + "&name=" + playlistname
+ ")")
614 dialog
= xbmcgui
.Dialog()
615 dialog
.ok('Grooveshark XBMC', 'You must be logged in', 'to delete a song from a Grooveshark playlist.')
617 # Find similar artists to searched artist
618 def similarArtists(self
, artistId
):
619 similar
= groovesharkApi
.getSimilarArtists(artistId
, limit
= self
.artistsearchlimit
)
620 if (len(similar
) > 0):
621 self
._add
_artists
_directory
(similar
)
623 dialog
= xbmcgui
.Dialog()
624 dialog
.ok('Grooveshark XBMC', 'No similar artists.')
628 def _get_keyboard(self
, default
="", heading
="", hidden
=False):
629 kb
= xbmc
.Keyboard(default
, heading
, hidden
)
631 if (kb
.isConfirmed()):
632 return unicode(kb
.getText(), "utf-8")
635 # Login to grooveshark
636 def _get_login(self
):
637 if (self
.username
== "" or self
.password
== ""):
638 dialog
= xbmcgui
.Dialog()
639 dialog
.ok('Grooveshark XBMC', 'Unable to login.', 'Check username and password in settings.')
643 uid
= groovesharkApi
.login(self
.username
, self
.password
)
647 dialog
= xbmcgui
.Dialog()
648 dialog
.ok('Grooveshark XBMC', 'Unable to login.', 'Check username and password in settings.')
651 # Get a song directory item
652 def _get_song_item(self
, song
, trackLabelFormat
):
658 return self
.songItem(songid
, name
, album
, artist
, coverart
, trackLabelFormat
)
661 def _get_icon(self
, url
, songid
):
663 localThumb
= os
.path
.join(xbmc
.translatePath(os
.path
.join(thumbDir
, str(songid
)))) + '.tbn'
665 if os
.path
.isfile(localThumb
) == False:
666 loc
= urllib
.URLopener()
667 loc
.retrieve(url
, localThumb
)
669 shutil
.copy2(thumbDef
, localThumb
)
670 return os
.path
.join(os
.path
.join(thumbDir
, str(songid
))) + '.tbn'
674 # Add songs to directory
675 def _add_songs_directory(self
, songs
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
, page
=0, playlistid
=0, playlistname
='', isFavorites
=False):
677 totalSongs
= len(songs
)
681 if page
== 0 and totalSongs
<= self
.songspagelimit
:
682 xbmc
.log("Found " + str(totalSongs
) + " songs...")
687 self
._setSavedSongs
(songs
)
689 songs
= self
._getSavedSongs
()
690 totalSongs
= len(songs
)
693 start
= page
* self
.songspagelimit
694 end
= start
+ self
.songspagelimit
695 songs
= songs
[start
:end
]
699 item
= self
._get
_song
_item
(song
, trackLabelFormat
)
700 coverart
= item
.getProperty('coverart')
707 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
) \
708 +"&album="+urllib
.quote_plus(songalbum
) \
709 +"&artist="+urllib
.quote_plus(songartist
) \
710 +"&coverart="+urllib
.quote_plus(coverart
)
711 fav
=sys
.argv
[0]+"?mode="+str(MODE_FAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)
712 unfav
=sys
.argv
[0]+"?mode="+str(MODE_UNFAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)+"&prevmode="
714 if isFavorites
== True:
715 unfav
= unfav
+str(MODE_FAVORITES
)
717 menuItems
.append(("Grooveshark favorite", "XBMC.RunPlugin("+fav
+")"))
718 menuItems
.append(("Not Grooveshark favorite", "XBMC.RunPlugin("+unfav
+")"))
720 rmplaylstsong
=sys
.argv
[0]+"?playlistid="+str(playlistid
)+"&id="+str(songid
)+"&mode="+str(MODE_REMOVE_PLAYLIST_SONG
)+"&name="+playlistname
721 menuItems
.append(("Remove from Grooveshark playlist", "XBMC.RunPlugin("+rmplaylstsong
+")"))
723 addplaylstsong
=sys
.argv
[0]+"?id="+str(songid
)+"&mode="+str(MODE_ADD_PLAYLIST_SONG
)
724 menuItems
.append(("Add to Grooveshark playlist", "XBMC.RunPlugin("+addplaylstsong
+")"))
725 item
.addContextMenuItems(menuItems
, replaceItems
=False)
726 xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=item
,isFolder
=False, totalItems
=len(songs
))
730 if totalSongs
> page
* self
.songspagelimit
:
731 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG_PAGE
)+"&id=playlistid"+"&page="+str(page
)+"&label="+str(trackLabelFormat
)+"&name="+playlistname
732 self
._add
_dir
('More songs...', u
, MODE_SONG_PAGE
, self
.songImg
, 0, totalSongs
- (page
* self
.songspagelimit
))
734 xbmcplugin
.setContent(self
._handle
, 'songs')
735 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
737 # Add albums to directory
738 def _add_albums_directory(self
, albums
, artistid
=0):
740 xbmc
.log("Found " + str(n
) + " albums...")
744 albumArtistName
= album
[0]
747 albumImage
= self
._get
_icon
(album
[4], 'album-' + str(albumID
))
748 self
._add
_dir
(albumName
+ " - " + albumArtistName
, '', MODE_ALBUM
, albumImage
, albumID
, n
)
750 # Not supported by key
752 # self._add_dir('Similar artists...', '', MODE_SIMILAR_ARTISTS, self.artistImg, artistid)
753 xbmcplugin
.setContent(self
._handle
, 'albums')
754 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ALBUM_IGNORE_THE
)
755 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
757 # Add artists to directory
758 def _add_artists_directory(self
, artists
):
760 xbmc
.log("Found " + str(n
) + " artists...")
764 artistName
= artist
[0]
766 self
._add
_dir
(artistName
, '', MODE_ARTIST
, self
.artistImg
, artistID
, n
)
768 xbmcplugin
.setContent(self
._handle
, 'artists')
769 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ARTIST_IGNORE_THE
)
770 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
772 # Add playlists to directory
773 def _add_playlists_directory(self
, playlists
):
775 xbmc
.log("Found " + str(n
) + " playlists...")
778 playlist
= playlists
[i
]
779 playlistName
= playlist
[0]
780 playlistID
= playlist
[1]
781 dir = self
._add
_dir
(playlistName
, '', MODE_PLAYLIST
, self
.playlistImg
, playlistID
, n
)
783 xbmcplugin
.setContent(self
._handle
, 'files')
784 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_LABEL
)
785 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
787 # Add whatever directory
788 def _add_dir(self
, name
, url
, mode
, iconimage
, id, items
=1):
791 u
=sys
.argv
[0]+"?mode="+str(mode
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
794 dir=xbmcgui
.ListItem(name
, iconImage
=iconimage
, thumbnailImage
=iconimage
)
795 dir.setInfo( type="Music", infoLabels
={ "title": name
} )
799 if mode
== MODE_ALBUM
:
800 mkplaylst
=sys
.argv
[0]+"?mode="+str(MODE_MAKE_PLAYLIST
)+"&name="+name
+"&id="+str(id)
801 menuItems
.append(("Make Grooveshark playlist", "XBMC.RunPlugin("+mkplaylst
+")"))
802 # Broken rename/delete are broken in API
803 if mode
== MODE_PLAYLIST
:
804 rmplaylst
=sys
.argv
[0]+"?mode="+str(MODE_REMOVE_PLAYLIST
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
805 menuItems
.append(("Delete Grooveshark playlist", "XBMC.RunPlugin("+rmplaylst
+")"))
806 mvplaylst
=sys
.argv
[0]+"?mode="+str(MODE_RENAME_PLAYLIST
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
807 menuItems
.append(("Rename Grooveshark playlist", "XBMC.RunPlugin("+mvplaylst
+")"))
808 dir.addContextMenuItems(menuItems
, replaceItems
=False)
810 return xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=dir,isFolder
=True, totalItems
=items
)
812 def _getSavedSongs(self
):
813 path
= os
.path
.join(cacheDir
, 'songs.dmp')
816 songs
= pickle
.load(f
)
823 def _setSavedSongs(self
, songs
):
825 # Create the 'data' directory if it doesn't exist.
826 if not os
.path
.exists(cacheDir
):
827 os
.makedirs(cacheDir
)
828 path
= os
.path
.join(cacheDir
, 'songs.dmp')
830 pickle
.dump(songs
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
833 xbmc
.log("An error occurred saving songs")
836 def _getSongDuration(self
, songid
):
837 path
= os
.path
.join(cacheDir
, 'duration.dmp')
845 durations
= pickle
.load(f
)
846 for song
in durations
:
854 stream
= groovesharkApi
.getSubscriberStreamKey(songid
)
855 usecs
= stream
['uSecs']
857 usecs
= usecs
* 10 # Some durations are 10x to small
858 duration
= usecs
/ 1000000
859 song
= [id, duration
]
860 durations
.append(song
)
861 self
._setSongDuration
(durations
)
865 def _setSongDuration(self
, durations
):
867 # Create the 'data' directory if it doesn't exist.
868 if not os
.path
.exists(cacheDir
):
869 os
.makedirs(cacheDir
)
870 path
= os
.path
.join(cacheDir
, 'duration.dmp')
872 pickle
.dump(durations
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
875 xbmc
.log("An error occurred saving durations")
879 # Parse URL parameters
882 paramstring
=sys
.argv
[2]
883 xbmc
.log(paramstring
)
884 if len(paramstring
)>=2:
886 cleanedparams
=params
.replace('?','')
887 if (params
[len(params
)-1]=='/'):
888 params
=params
[0:len(params
)-2]
889 pairsofparams
=cleanedparams
.split('&')
891 for i
in range(len(pairsofparams
)):
893 splitparams
=pairsofparams
[i
].split('=')
894 if (len(splitparams
))==2:
895 param
[splitparams
[0]]=splitparams
[1]
899 grooveshark
= Groveshark();
903 try: mode
=int(params
["mode"])
906 try: id=int(params
["id"])
909 try: name
=urllib
.unquote_plus(params
["name"])
912 # Call function for URL
914 grooveshark
.categories()
916 elif mode
==MODE_SEARCH_SONGS
:
917 grooveshark
.searchSongs()
919 elif mode
==MODE_SEARCH_ALBUMS
:
920 grooveshark
.searchAlbums()
922 elif mode
==MODE_SEARCH_ARTISTS
:
923 grooveshark
.searchArtists()
925 elif mode
==MODE_SEARCH_ARTISTS_ALBUMS
:
926 grooveshark
.searchArtistsAlbums(name
)
928 elif mode
==MODE_SEARCH_PLAYLISTS
:
929 grooveshark
.searchPlaylists()
931 elif mode
==MODE_POPULAR_SONGS
:
932 grooveshark
.popularSongs()
934 elif mode
==MODE_ARTIST_POPULAR
:
935 grooveshark
.artistPopularSongs()
937 elif mode
==MODE_FAVORITES
:
938 grooveshark
.favorites()
940 elif mode
==MODE_PLAYLISTS
:
941 grooveshark
.playlists()
943 elif mode
==MODE_SONG_PAGE
:
944 try: page
=urllib
.unquote_plus(params
["page"])
946 try: label
=urllib
.unquote_plus(params
["label"])
948 grooveshark
.songPage(page
, label
, id, name
)
950 elif mode
==MODE_SONG
:
951 try: album
=urllib
.unquote_plus(params
["album"])
953 try: artist
=urllib
.unquote_plus(params
["artist"])
955 try: coverart
=urllib
.unquote_plus(params
["coverart"])
957 song
= grooveshark
.songItem(id, name
, album
, artist
, coverart
)
958 grooveshark
.playSong(song
)
960 elif mode
==MODE_ARTIST
:
961 grooveshark
.artist(id)
963 elif mode
==MODE_ALBUM
:
964 grooveshark
.album(id)
966 elif mode
==MODE_PLAYLIST
:
967 grooveshark
.playlist(id, name
)
969 elif mode
==MODE_FAVORITE
:
970 grooveshark
.favorite(id)
972 elif mode
==MODE_UNFAVORITE
:
973 try: prevMode
=int(urllib
.unquote_plus(params
["prevmode"]))
976 grooveshark
.unfavorite(id, prevMode
)
978 elif mode
==MODE_SIMILAR_ARTISTS
:
979 grooveshark
.similarArtists(id)
981 elif mode
==MODE_MAKE_PLAYLIST
:
982 grooveshark
.makePlaylist(id, name
)
984 elif mode
==MODE_REMOVE_PLAYLIST
:
985 grooveshark
.removePlaylist(id, name
)
987 elif mode
==MODE_RENAME_PLAYLIST
:
988 grooveshark
.renamePlaylist(id, name
)
990 elif mode
==MODE_REMOVE_PLAYLIST_SONG
:
991 try: playlistID
=urllib
.unquote_plus(params
["playlistid"])
993 grooveshark
.removePlaylistSong(playlistID
, name
, id)
995 elif mode
==MODE_ADD_PLAYLIST_SONG
:
996 grooveshark
.addPlaylistSong(id)
999 xbmcplugin
.endOfDirectory(int(sys
.argv
[1]))