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
29 MODE_SEARCH_ALBUMS
= 2
30 MODE_SEARCH_ARTISTS
= 3
31 MODE_SEARCH_ARTISTS_ALBUMS
= 4
32 MODE_SEARCH_PLAYLISTS
= 5
33 MODE_ARTIST_POPULAR
= 6
34 MODE_POPULAR_SONGS
= 7
41 MODE_SIMILAR_ARTISTS
= 14
45 MODE_MAKE_PLAYLIST
= 18
46 MODE_REMOVE_PLAYLIST
= 19
47 MODE_RENAME_PLAYLIST
= 20
48 MODE_REMOVE_PLAYLIST_SONG
= 21
49 MODE_ADD_PLAYLIST_SONG
= 22
56 ACTION_SELECT_ITEM
= 7
57 ACTION_PREVIOUS_MENU
= 10
59 # Formats for track labels
60 ARTIST_ALBUM_NAME_LABEL
= 0
61 NAME_ALBUM_ARTIST_LABEL
= 1
63 # Stream marking time (seconds)
64 STREAM_MARKING_TIME
= 30
67 player
= xbmc
.Player()
71 resDir
= xbmc
.translatePath(os
.path
.join(baseDir
, 'resources'))
72 libDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'lib'))
73 imgDir
= xbmc
.translatePath(os
.path
.join(resDir
, 'img'))
74 cacheDir
= os
.path
.join(xbmc
.translatePath('special://masterprofile/addon_data/'), os
.path
.basename(baseDir
))
75 thumbDirName
= 'thumb'
76 thumbDir
= os
.path
.join('special://masterprofile/addon_data/', os
.path
.basename(baseDir
), thumbDirName
)
78 baseModeUrl
= 'plugin://plugin.audio.groove/'
79 playlistUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLIST
)
80 playlistsUrl
= baseModeUrl
+ '?mode=' + str(MODE_PLAYLISTS
)
81 favoritesUrl
= baseModeUrl
+ '?mode=' + str(MODE_FAVORITES
)
83 searchArtistsAlbumsName
= __language__(30006)
85 thumbDef
= os
.path
.join(imgDir
, 'default.tbn')
86 listBackground
= os
.path
.join(imgDir
, 'listbackground.png')
88 sys
.path
.append (libDir
)
89 from GroovesharkAPI
import GrooveAPI
90 from threading
import Event
, Thread
93 groovesharkApi
= GrooveAPI()
94 if groovesharkApi
.pingService() != True:
95 raise StandardError(__language__(30007))
97 dialog
= xbmcgui
.Dialog(__language__(30008),__language__(30009),__language__(30010))
101 # Mark song as playing or played
102 def markSong(songid
, duration
):
106 if player
.isPlayingAudio():
107 tNow
= player
.getTime()
108 if tNow
>= STREAM_MARKING_TIME
and songMarkTime
== 0:
109 groovesharkApi
.markStreamKeyOver30Secs()
111 elif duration
> tNow
and duration
- tNow
< 2 and songMarkTime
>= STREAM_MARKING_TIME
:
114 groovesharkApi
.markSongComplete(songid
)
120 def __init__( self
, *args
, **kwargs
):
121 self
.__dict
__.update( kwargs
)
123 # Window dialog to select a grooveshark playlist
124 class GroovesharkPlaylistSelect(xbmcgui
.WindowDialog
):
126 def __init__(self
, items
=[]):
127 gap
= int(self
.getHeight()/100)
128 w
= int(self
.getWidth()*0.5)
129 h
= self
.getHeight()-30*gap
131 rh
= self
.getHeight()
135 self
.imgBg
= xbmcgui
.ControlImage(x
+gap
, 5*gap
+y
, w
-2*gap
, h
-5*gap
, listBackground
)
136 self
.addControl(self
.imgBg
)
138 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)
139 self
.addControl(self
.playlistControl
)
142 self
.isSelecting
= False
145 for playlist
in items
:
146 listitems
.append(xbmcgui
.ListItem(playlist
[0]))
147 listitems
.append(xbmcgui
.ListItem(__language__(30011)))
148 self
.playlistControl
.addItems(listitems
)
149 self
.setFocus(self
.playlistControl
)
150 self
.playlistControl
.selectItem(0)
151 item
= self
.playlistControl
.getListItem(self
.lastPos
)
154 # Highlight selected item
155 def setHighlight(self
):
159 self
.isSelecting
= True
161 pos
= self
.playlistControl
.getSelectedPosition()
163 item
= self
.playlistControl
.getListItem(self
.lastPos
)
165 item
= self
.playlistControl
.getListItem(pos
)
168 self
.isSelecting
= False
171 def onControl(self
, control
):
172 if control
== self
.playlistControl
:
173 self
.selected
= self
.playlistControl
.getSelectedPosition()
176 # Action - close or up/down
177 def onAction(self
, action
):
178 if action
== ACTION_PREVIOUS_MENU
:
181 elif action
== ACTION_MOVE_UP
or action
== ACTION_MOVE_DOWN
or action
== ACTION_PAGE_UP
or action
== ACTION_PAGE_DOWN
== 6:
182 self
.setFocus(self
.playlistControl
)
186 class PlayTimer(Thread
):
187 # interval -- floating point number specifying the number of seconds to wait before executing function
188 # function -- the function (or callable object) to be executed
190 # iterations -- integer specifying the number of iterations to perform
191 # args -- list of positional arguments passed to function
192 # kwargs -- dictionary of keyword arguments passed to function
194 def __init__(self
, interval
, function
, iterations
=0, args
=[], kwargs
={}):
195 Thread
.__init
__(self
)
196 self
.interval
= interval
197 self
.function
= function
198 self
.iterations
= iterations
201 self
.finished
= Event()
205 while not self
.finished
.isSet() and (self
.iterations
<= 0 or count
< self
.iterations
):
206 self
.finished
.wait(self
.interval
)
207 if not self
.finished
.isSet():
208 self
.function(*self
.args
, **self
.kwargs
)
214 def setIterations(self
, iterations
):
215 self
.iterations
= iterations
219 return self
.iterations
* self
.interval
224 albumImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'album.png'))
225 artistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artist.png'))
226 artistsAlbumsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'artistsalbums.png'))
227 favoritesImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'favorites.png'))
228 playlistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'playlist.png'))
229 usersplaylistsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'usersplaylists.png'))
230 popularSongsImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongs.png'))
231 popularSongsArtistImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'popularSongsArtist.png'))
232 songImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'song.png'))
233 defImg
= xbmc
.translatePath(os
.path
.join(imgDir
, 'default.tbn'))
234 fanImg
= xbmc
.translatePath(os
.path
.join(baseDir
, 'fanart.png'))
236 settings
= xbmcaddon
.Addon(id='plugin.audio.groove')
237 songsearchlimit
= int(settings
.getSetting('songsearchlimit'))
238 albumsearchlimit
= int(settings
.getSetting('albumsearchlimit'))
239 artistsearchlimit
= int(settings
.getSetting('artistsearchlimit'))
240 songspagelimit
= int(settings
.getSetting('songspagelimit'))
241 username
= settings
.getSetting('username')
242 password
= settings
.getSetting('password')
245 def __init__( self
):
246 self
._handle
= int(sys
.argv
[1])
247 if os
.path
.isdir(cacheDir
) == False:
248 os
.makedirs(cacheDir
)
249 xbmc
.log(__language__(30012) + " " + cacheDir
)
250 artDir
= xbmc
.translatePath(thumbDir
)
251 if os
.path
.isdir(artDir
) == False:
253 xbmc
.log(__language__(30012) + " " + artDir
)
256 def categories(self
):
258 self
.userid
= self
._get
_login
()
261 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
263 self
._add
_dir
(__language__(30013), '', MODE_SEARCH_SONGS
, self
.songImg
, 0)
264 self
._add
_dir
(__language__(30014), '', MODE_SEARCH_ALBUMS
, self
.albumImg
, 0)
265 self
._add
_dir
(__language__(30015), '', MODE_SEARCH_ARTISTS
, self
.artistImg
, 0)
266 self
._add
_dir
(searchArtistsAlbumsName
, '', MODE_SEARCH_ARTISTS_ALBUMS
, self
.artistsAlbumsImg
, 0)
267 # Not supported by key
268 #self._add_dir("Search for user's playlists...", '', MODE_SEARCH_PLAYLISTS, self.usersplaylistsImg, 0)
269 self
._add
_dir
(__language__(30016), '', MODE_ARTIST_POPULAR
, self
.popularSongsArtistImg
, 0)
270 self
._add
_dir
(__language__(30017), '', MODE_POPULAR_SONGS
, self
.popularSongsImg
, 0)
271 if (self
.userid
!= 0):
272 self
._add
_dir
(__language__(30018), '', MODE_FAVORITES
, self
.favoritesImg
, 0)
273 self
._add
_dir
(__language__(30019), '', MODE_PLAYLISTS
, self
.playlistImg
, 0)
276 def searchSongs(self
):
277 query
= self
._get
_keyboard
(default
="", heading
=__language__(30020))
279 songs
= groovesharkApi
.getSongSearchResults(query
, limit
= self
.songsearchlimit
)
281 self
._add
_songs
_directory
(songs
)
283 dialog
= xbmcgui
.Dialog()
284 dialog
.ok(__language__(30008), __language__(30021))
290 def searchAlbums(self
):
291 query
= self
._get
_keyboard
(default
="", heading
=__language__(30022))
293 albums
= groovesharkApi
.getAlbumSearchResults(query
, limit
= self
.albumsearchlimit
)
294 if (len(albums
) > 0):
295 self
._add
_albums
_directory
(albums
)
297 dialog
= xbmcgui
.Dialog()
298 dialog
.ok(__language__(30008), __language__(30023))
304 def searchArtists(self
):
305 query
= self
._get
_keyboard
(default
="", heading
=__language__(30024))
307 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
308 if (len(artists
) > 0):
309 self
._add
_artists
_directory
(artists
)
311 dialog
= xbmcgui
.Dialog()
312 dialog
.ok(__language__(30008), __language__(30025))
317 # Search for playlists
318 def searchPlaylists(self
):
319 query
= self
._get
_keyboard
(default
="", heading
=__language__(30026))
321 playlists
= groovesharkApi
.getUserPlaylistsByUsername(query
)
322 if (len(playlists
) > 0):
323 self
._add
_playlists
_directory
(playlists
)
325 dialog
= xbmcgui
.Dialog()
326 dialog
.ok(__language__(30008), __language__(30027))
331 # Search for artists albums
332 def searchArtistsAlbums(self
, artistName
= None):
333 if artistName
== None or artistName
== searchArtistsAlbumsName
:
334 query
= self
._get
_keyboard
(default
="", heading
=__language__(30028))
338 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
339 if (len(artists
) > 0):
342 xbmc
.log("Found " + artist
[0] + "...")
343 albums
= groovesharkApi
.getArtistAlbums(artistID
, limit
= self
.albumsearchlimit
)
344 if (len(albums
) > 0):
345 self
._add
_albums
_directory
(albums
, artistID
)
347 dialog
= xbmcgui
.Dialog()
348 dialog
.ok(__language__(30008), __language__(30029))
351 dialog
= xbmcgui
.Dialog()
352 dialog
.ok(__language__(30008), __language__(30030))
359 userid
= self
._get
_login
()
361 favorites
= groovesharkApi
.getUserFavoriteSongs()
362 if (len(favorites
) > 0):
363 self
._add
_songs
_directory
(favorites
, isFavorites
=True)
365 dialog
= xbmcgui
.Dialog()
366 dialog
.ok(__language__(30008), __language__(30031))
370 def popularSongs(self
):
371 popular
= groovesharkApi
.getPopularSongsToday(limit
= self
.songsearchlimit
)
372 if (len(popular
) > 0):
373 self
._add
_songs
_directory
(popular
)
375 dialog
= xbmcgui
.Dialog()
376 dialog
.ok(__language__(30008), __language__(30032))
381 userid
= self
._get
_login
()
383 playlists
= groovesharkApi
.getUserPlaylists()
384 if (len(playlists
) > 0):
385 self
._add
_playlists
_directory
(playlists
)
387 dialog
= xbmcgui
.Dialog()
388 dialog
.ok(__language__(30008), __language__(30033))
391 dialog
= xbmcgui
.Dialog()
392 dialog
.ok(__language__(30008), __language__(30034), __language__(30035))
394 # Make songs a favorite
395 def favorite(self
, songid
):
396 userid
= self
._get
_login
()
398 xbmc
.log("Favorite song: " + str(songid
))
399 groovesharkApi
.addUserFavoriteSong(songID
= songid
)
400 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30036) + ', 1000, ' + thumbDef
+ ')')
402 dialog
= xbmcgui
.Dialog()
403 dialog
.ok(__language__(30008), __language__(30034), __language__(30037))
405 # Remove song from favorites
406 def unfavorite(self
, songid
, prevMode
=0):
407 userid
= self
._get
_login
()
409 xbmc
.log("Unfavorite song: " + str(songid
) + ', previous mode was ' + str(prevMode
))
410 groovesharkApi
.removeUserFavoriteSongs(songIDs
= songid
)
411 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30038) + ', 1000, ' + thumbDef
+ ')')
412 # Refresh to remove item from directory
413 if (int(prevMode
) == MODE_FAVORITES
):
414 xbmc
.executebuiltin("Container.Refresh(" + favoritesUrl
+ ")")
416 dialog
= xbmcgui
.Dialog()
417 dialog
.ok(__language__(30008), __language__(30034), __language__(30039))
420 # Show selected album
421 def album(self
, albumid
):
422 album
= groovesharkApi
.getAlbumSongs(albumid
, limit
= self
.songsearchlimit
)
423 self
._add
_songs
_directory
(album
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
425 # Show selected artist
426 def artist(self
, artistid
):
427 albums
= groovesharkApi
.getArtistAlbums(artistid
, limit
= self
.albumsearchlimit
)
428 self
._add
_albums
_directory
(albums
, artistid
)
430 # Show selected playlist
431 def playlist(self
, playlistid
, playlistname
):
432 userid
= self
._get
_login
()
434 songs
= groovesharkApi
.getPlaylistSongs(playlistid
)
435 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
, playlistid
=playlistid
, playlistname
=playlistname
)
437 dialog
= xbmcgui
.Dialog()
438 dialog
.ok(__language__(30008), __language__(30034), __language__(30040))
440 # Show popular songs of the artist
441 def artistPopularSongs(self
):
442 query
= self
._get
_keyboard
(default
="", heading
=__language__(30041))
444 artists
= groovesharkApi
.getArtistSearchResults(query
, limit
= self
.artistsearchlimit
)
445 if (len(artists
) > 0):
448 xbmc
.log("Found " + artist
[0] + "...")
449 songs
= groovesharkApi
.getArtistPopularSongs(artistID
, limit
= self
.songsearchlimit
)
451 self
._add
_songs
_directory
(songs
, trackLabelFormat
=NAME_ALBUM_ARTIST_LABEL
)
453 dialog
= xbmcgui
.Dialog()
454 dialog
.ok(__language__(30008), __language__(30042))
457 dialog
= xbmcgui
.Dialog()
458 dialog
.ok(__language__(30008), __language__(30043))
464 def playSong(self
, item
):
468 songid
= item
.getProperty('songid')
469 stream
= groovesharkApi
.getSubscriberStreamKey(songid
)
472 xbmc
.log("Grooveshark playing: " + url
)
473 xbmcplugin
.setResolvedUrl(handle
=int(sys
.argv
[1]), succeeded
=True, listitem
=item
)
474 # Wait for play then start time
476 while seconds
< STREAM_MARKING_TIME
:
478 if player
.isPlayingAudio() == True:
479 if playTimer
!= None:
482 duration
= int(item
.getProperty('duration'))
483 playTimer
= PlayTimer(1, markSong
, duration
, [songid
, duration
])
488 seconds
= seconds
+ 1
490 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ', ' + __language__(30044) + ', 1000, ' + thumbDef
+ ')')
492 # Make a song directory item
493 def songItem(self
, songid
, name
, album
, artist
, coverart
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
):
494 songImg
= self
._get
_icon
(coverart
, 'song-' + str(songid
) + "-image")
495 if int(trackLabelFormat
) == NAME_ALBUM_ARTIST_LABEL
:
496 trackLabel
= name
+ " - " + album
+ " - " + artist
498 trackLabel
= artist
+ " - " + album
+ " - " + name
499 duration
= self
._getSongDuration
(songid
)
500 item
= xbmcgui
.ListItem(label
= trackLabel
, thumbnailImage
=songImg
, iconImage
=songImg
)
501 item
.setInfo( type="music", infoLabels
={ "title": name
, "album": album
, "artist": artist
, "duration": duration
} )
502 item
.setProperty('mimetype', 'audio/mpeg')
503 item
.setProperty("IsPlayable", "true")
504 item
.setProperty('songid', str(songid
))
505 item
.setProperty('coverart', songImg
)
506 item
.setProperty('title', name
)
507 item
.setProperty('album', album
)
508 item
.setProperty('artist', artist
)
509 item
.setProperty('duration', str(duration
))
514 def songPage(self
, page
, trackLabelFormat
, playlistid
= 0, playlistname
= ''):
515 self
._add
_songs
_directory
([], trackLabelFormat
, page
, playlistid
= playlistid
, playlistname
= playlistname
)
517 # Make a playlist from an album
518 def makePlaylist(self
, albumid
, name
):
519 userid
= self
._get
_login
()
521 re
.split(' - ',name
,1)
522 nameTokens
= re
.split(' - ',name
,1) # suggested name
523 name
= self
._get
_keyboard
(default
=nameTokens
[0], heading
=__language__(30045))
525 album
= groovesharkApi
.getAlbumSongs(albumid
, limit
= self
.songsearchlimit
)
528 songids
.append(song
[1])
529 if groovesharkApi
.createPlaylist(name
, songids
) == 0:
530 dialog
= xbmcgui
.Dialog()
531 dialog
.ok(__language__(30008), __language__(30046), name
)
533 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30047)+ ', 1000, ' + thumbDef
+ ')')
535 dialog
= xbmcgui
.Dialog()
536 dialog
.ok(__language__(30008), __language__(30034), __language__(30048))
539 def renamePlaylist(self
, playlistid
, name
):
540 userid
= self
._get
_login
()
542 newname
= self
._get
_keyboard
(default
=name
, heading
=__language__(30049))
545 elif groovesharkApi
.playlistRename(playlistid
, newname
) == 0:
546 dialog
= xbmcgui
.Dialog()
547 dialog
.ok(__language__(30008), __language__(30050), name
)
549 # Refresh to show new item name
550 xbmc
.executebuiltin("Container.Refresh")
552 dialog
= xbmcgui
.Dialog()
553 dialog
.ok(__language__(30008), __language__(30034), __language__(30051))
556 def removePlaylist(self
, playlistid
, name
):
557 dialog
= xbmcgui
.Dialog()
558 if dialog
.yesno(__language__(30008), name
, __language__(30052)) == True:
559 userid
= self
._get
_login
()
561 if groovesharkApi
.playlistDelete(playlistid
) == 0:
562 dialog
= xbmcgui
.Dialog()
563 dialog
.ok(__language__(30008), __language__(30053), name
)
565 # Refresh to remove item from directory
566 xbmc
.executebuiltin("Container.Refresh(" + playlistsUrl
+ ")")
568 dialog
= xbmcgui
.Dialog()
569 dialog
.ok(__language__(30008), __language__(30034), __language__(30054))
571 # Add song to playlist
572 def addPlaylistSong(self
, songid
):
573 userid
= self
._get
_login
()
575 playlists
= groovesharkApi
.getUserPlaylists()
576 if (len(playlists
) > 0):
578 # Select the playlist
579 playlistSelect
= GroovesharkPlaylistSelect(items
=playlists
)
580 playlistSelect
.setFocus(playlistSelect
.playlistControl
)
581 playlistSelect
.doModal()
582 i
= playlistSelect
.selected
586 if i
>= len(playlists
):
587 name
= self
._get
_keyboard
(default
='', heading
=__language__(30055))
590 songIds
.append(songid
)
591 if groovesharkApi
.createPlaylist(name
, songIds
) == 0:
592 dialog
= xbmcgui
.Dialog()
593 dialog
.ok(__language__(30008), __language__(30056), name
)
595 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30057) + ', 1000, ' + thumbDef
+ ')')
598 playlist
= playlists
[i
]
599 playlistid
= playlist
[1]
600 xbmc
.log("Add song " + str(songid
) + " to playlist " + str(playlistid
))
602 songs
= groovesharkApi
.getPlaylistSongs(playlistid
)
604 songIDs
.append(song
[1])
605 songIDs
.append(songid
)
606 ret
= groovesharkApi
.setPlaylistSongs(playlistid
, songIDs
)
608 dialog
= xbmcgui
.Dialog()
609 dialog
.ok(__language__(30008), __language__(30058))
611 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30059) + ', 1000, ' + thumbDef
+ ')')
613 dialog
= xbmcgui
.Dialog()
614 dialog
.ok(__language__(30008), __language__(30060))
617 dialog
= xbmcgui
.Dialog()
618 dialog
.ok(__language__(30008), __language__(30034), __language__(30061))
620 # Remove song from playlist
621 def removePlaylistSong(self
, playlistid
, playlistname
, songid
):
622 dialog
= xbmcgui
.Dialog()
623 if dialog
.yesno(__language__(30008), __language__(30062), __language__(30063)) == True:
624 userid
= self
._get
_login
()
626 songs
= groovesharkApi
.getPlaylistSongs(playlistID
)
629 if (song
[1] != songid
):
630 songIDs
.append(song
[1])
631 ret
= groovesharkApi
.setPlaylistSongs(playlistID
, songIDs
)
633 dialog
= xbmcgui
.Dialog()
634 dialog
.ok(__language__(30008), __language__(30064), __language__(30065))
636 # Refresh to remove item from directory
637 xbmc
.executebuiltin('XBMC.Notification(' + __language__(30008) + ',' + __language__(30066)+ ', 1000, ' + thumbDef
+ ')')
638 xbmc
.executebuiltin("Container.Update(" + playlistUrl
+ "&id="+str(playlistid
) + "&name=" + playlistname
+ ")")
640 dialog
= xbmcgui
.Dialog()
641 dialog
.ok(__language__(30008), __language__(30034), __language__(30067))
643 # Find similar artists to searched artist
644 def similarArtists(self
, artistId
):
645 similar
= groovesharkApi
.getSimilarArtists(artistId
, limit
= self
.artistsearchlimit
)
646 if (len(similar
) > 0):
647 self
._add
_artists
_directory
(similar
)
649 dialog
= xbmcgui
.Dialog()
650 dialog
.ok(__language__(30008), __language__(30068))
654 def _get_keyboard(self
, default
="", heading
="", hidden
=False):
655 kb
= xbmc
.Keyboard(default
, heading
, hidden
)
657 if (kb
.isConfirmed()):
658 return unicode(kb
.getText(), "utf-8")
661 # Login to grooveshark
662 def _get_login(self
):
663 if (self
.username
== "" or self
.password
== ""):
664 dialog
= xbmcgui
.Dialog()
665 dialog
.ok(__language__(30008), __language__(30069), __language__(30070))
669 uid
= groovesharkApi
.login(self
.username
, self
.password
)
673 dialog
= xbmcgui
.Dialog()
674 dialog
.ok(__language__(30008), __language__(30069), __language__(30070))
677 # Get a song directory item
678 def _get_song_item(self
, song
, trackLabelFormat
):
684 return self
.songItem(songid
, name
, album
, artist
, coverart
, trackLabelFormat
)
687 def _get_icon(self
, url
, songid
):
689 localThumb
= os
.path
.join(xbmc
.translatePath(os
.path
.join(thumbDir
, str(songid
)))) + '.tbn'
691 if os
.path
.isfile(localThumb
) == False:
692 loc
= urllib
.URLopener()
693 loc
.retrieve(url
, localThumb
)
695 shutil
.copy2(thumbDef
, localThumb
)
696 return os
.path
.join(os
.path
.join(thumbDir
, str(songid
))) + '.tbn'
700 # Add songs to directory
701 def _add_songs_directory(self
, songs
, trackLabelFormat
=ARTIST_ALBUM_NAME_LABEL
, page
=0, playlistid
=0, playlistname
='', isFavorites
=False):
703 totalSongs
= len(songs
)
707 if page
== 0 and totalSongs
<= self
.songspagelimit
:
708 xbmc
.log("Found " + str(totalSongs
) + " songs...")
713 self
._setSavedSongs
(songs
)
715 songs
= self
._getSavedSongs
()
716 totalSongs
= len(songs
)
719 start
= page
* self
.songspagelimit
720 end
= start
+ self
.songspagelimit
721 songs
= songs
[start
:end
]
725 item
= self
._get
_song
_item
(song
, trackLabelFormat
)
726 coverart
= item
.getProperty('coverart')
733 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
) \
734 +"&album="+urllib
.quote_plus(songalbum
) \
735 +"&artist="+urllib
.quote_plus(songartist
) \
736 +"&coverart="+urllib
.quote_plus(coverart
)
737 fav
=sys
.argv
[0]+"?mode="+str(MODE_FAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)
738 unfav
=sys
.argv
[0]+"?mode="+str(MODE_UNFAVORITE
)+"&name="+urllib
.quote_plus(songname
)+"&id="+str(songid
)+"&prevmode="
740 if isFavorites
== True:
741 unfav
= unfav
+str(MODE_FAVORITES
)
743 menuItems
.append((__language__(30071), "XBMC.RunPlugin("+fav
+")"))
744 menuItems
.append((__language__(30072), "XBMC.RunPlugin("+unfav
+")"))
746 rmplaylstsong
=sys
.argv
[0]+"?playlistid="+str(playlistid
)+"&id="+str(songid
)+"&mode="+str(MODE_REMOVE_PLAYLIST_SONG
)+"&name="+playlistname
747 menuItems
.append((__language__(30073), "XBMC.RunPlugin("+rmplaylstsong
+")"))
749 addplaylstsong
=sys
.argv
[0]+"?id="+str(songid
)+"&mode="+str(MODE_ADD_PLAYLIST_SONG
)
750 menuItems
.append((__language__(30074), "XBMC.RunPlugin("+addplaylstsong
+")"))
751 item
.addContextMenuItems(menuItems
, replaceItems
=False)
752 xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=item
,isFolder
=False, totalItems
=len(songs
))
756 if totalSongs
> page
* self
.songspagelimit
:
757 u
=sys
.argv
[0]+"?mode="+str(MODE_SONG_PAGE
)+"&id=playlistid"+"&page="+str(page
)+"&label="+str(trackLabelFormat
)+"&name="+playlistname
758 self
._add
_dir
(__language__(30075) + '...', u
, MODE_SONG_PAGE
, self
.songImg
, 0, totalSongs
- (page
* self
.songspagelimit
))
760 xbmcplugin
.setContent(self
._handle
, 'songs')
761 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
763 # Add albums to directory
764 def _add_albums_directory(self
, albums
, artistid
=0):
766 xbmc
.log("Found " + str(n
) + " albums...")
770 albumArtistName
= album
[0]
773 albumImage
= self
._get
_icon
(album
[4], 'album-' + str(albumID
))
774 self
._add
_dir
(albumName
+ " - " + albumArtistName
, '', MODE_ALBUM
, albumImage
, albumID
, n
)
776 # Not supported by key
778 # self._add_dir('Similar artists...', '', MODE_SIMILAR_ARTISTS, self.artistImg, artistid)
779 xbmcplugin
.setContent(self
._handle
, 'albums')
780 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ALBUM_IGNORE_THE
)
781 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
783 # Add artists to directory
784 def _add_artists_directory(self
, artists
):
786 xbmc
.log("Found " + str(n
) + " artists...")
790 artistName
= artist
[0]
792 self
._add
_dir
(artistName
, '', MODE_ARTIST
, self
.artistImg
, artistID
, n
)
794 xbmcplugin
.setContent(self
._handle
, 'artists')
795 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_ARTIST_IGNORE_THE
)
796 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
798 # Add playlists to directory
799 def _add_playlists_directory(self
, playlists
):
801 xbmc
.log("Found " + str(n
) + " playlists...")
804 playlist
= playlists
[i
]
805 playlistName
= playlist
[0]
806 playlistID
= playlist
[1]
807 dir = self
._add
_dir
(playlistName
, '', MODE_PLAYLIST
, self
.playlistImg
, playlistID
, n
)
809 xbmcplugin
.setContent(self
._handle
, 'files')
810 xbmcplugin
.addSortMethod(self
._handle
, xbmcplugin
.SORT_METHOD_LABEL
)
811 xbmcplugin
.setPluginFanart(int(sys
.argv
[1]), self
.fanImg
)
813 # Add whatever directory
814 def _add_dir(self
, name
, url
, mode
, iconimage
, id, items
=1):
817 u
=sys
.argv
[0]+"?mode="+str(mode
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
820 dir=xbmcgui
.ListItem(name
, iconImage
=iconimage
, thumbnailImage
=iconimage
)
821 dir.setInfo( type="Music", infoLabels
={ "title": name
} )
825 if mode
== MODE_ALBUM
:
826 mkplaylst
=sys
.argv
[0]+"?mode="+str(MODE_MAKE_PLAYLIST
)+"&name="+name
+"&id="+str(id)
827 menuItems
.append((__language__(30076), "XBMC.RunPlugin("+mkplaylst
+")"))
828 # Broken rename/delete are broken in API
829 if mode
== MODE_PLAYLIST
:
830 rmplaylst
=sys
.argv
[0]+"?mode="+str(MODE_REMOVE_PLAYLIST
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
831 menuItems
.append((__language__(30077), "XBMC.RunPlugin("+rmplaylst
+")"))
832 mvplaylst
=sys
.argv
[0]+"?mode="+str(MODE_RENAME_PLAYLIST
)+"&name="+urllib
.quote_plus(name
)+"&id="+str(id)
833 menuItems
.append((__language__(30078), "XBMC.RunPlugin("+mvplaylst
+")"))
834 dir.addContextMenuItems(menuItems
, replaceItems
=False)
836 return xbmcplugin
.addDirectoryItem(handle
=int(sys
.argv
[1]),url
=u
,listitem
=dir,isFolder
=True, totalItems
=items
)
838 def _getSavedSongs(self
):
839 path
= os
.path
.join(cacheDir
, 'songs.dmp')
842 songs
= pickle
.load(f
)
849 def _setSavedSongs(self
, songs
):
851 # Create the 'data' directory if it doesn't exist.
852 if not os
.path
.exists(cacheDir
):
853 os
.makedirs(cacheDir
)
854 path
= os
.path
.join(cacheDir
, 'songs.dmp')
856 pickle
.dump(songs
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
859 xbmc
.log("An error occurred saving songs")
862 def _getSongDuration(self
, songid
):
863 path
= os
.path
.join(cacheDir
, 'duration.dmp')
871 durations
= pickle
.load(f
)
872 for song
in durations
:
880 stream
= groovesharkApi
.getSubscriberStreamKey(songid
)
881 usecs
= stream
['uSecs']
883 usecs
= usecs
* 10 # Some durations are 10x to small
884 duration
= usecs
/ 1000000
885 song
= [id, duration
]
886 durations
.append(song
)
887 self
._setSongDuration
(durations
)
891 def _setSongDuration(self
, durations
):
893 # Create the 'data' directory if it doesn't exist.
894 if not os
.path
.exists(cacheDir
):
895 os
.makedirs(cacheDir
)
896 path
= os
.path
.join(cacheDir
, 'duration.dmp')
898 pickle
.dump(durations
, f
, protocol
=pickle
.HIGHEST_PROTOCOL
)
901 xbmc
.log("An error occurred saving durations")
905 # Parse URL parameters
908 paramstring
=sys
.argv
[2]
909 xbmc
.log(paramstring
)
910 if len(paramstring
)>=2:
912 cleanedparams
=params
.replace('?','')
913 if (params
[len(params
)-1]=='/'):
914 params
=params
[0:len(params
)-2]
915 pairsofparams
=cleanedparams
.split('&')
917 for i
in range(len(pairsofparams
)):
919 splitparams
=pairsofparams
[i
].split('=')
920 if (len(splitparams
))==2:
921 param
[splitparams
[0]]=splitparams
[1]
925 grooveshark
= Groveshark();
929 try: mode
=int(params
["mode"])
932 try: id=int(params
["id"])
935 try: name
=urllib
.unquote_plus(params
["name"])
938 # Call function for URL
940 grooveshark
.categories()
942 elif mode
==MODE_SEARCH_SONGS
:
943 grooveshark
.searchSongs()
945 elif mode
==MODE_SEARCH_ALBUMS
:
946 grooveshark
.searchAlbums()
948 elif mode
==MODE_SEARCH_ARTISTS
:
949 grooveshark
.searchArtists()
951 elif mode
==MODE_SEARCH_ARTISTS_ALBUMS
:
952 grooveshark
.searchArtistsAlbums(name
)
954 elif mode
==MODE_SEARCH_PLAYLISTS
:
955 grooveshark
.searchPlaylists()
957 elif mode
==MODE_POPULAR_SONGS
:
958 grooveshark
.popularSongs()
960 elif mode
==MODE_ARTIST_POPULAR
:
961 grooveshark
.artistPopularSongs()
963 elif mode
==MODE_FAVORITES
:
964 grooveshark
.favorites()
966 elif mode
==MODE_PLAYLISTS
:
967 grooveshark
.playlists()
969 elif mode
==MODE_SONG_PAGE
:
970 try: page
=urllib
.unquote_plus(params
["page"])
972 try: label
=urllib
.unquote_plus(params
["label"])
974 grooveshark
.songPage(page
, label
, id, name
)
976 elif mode
==MODE_SONG
:
977 try: album
=urllib
.unquote_plus(params
["album"])
979 try: artist
=urllib
.unquote_plus(params
["artist"])
981 try: coverart
=urllib
.unquote_plus(params
["coverart"])
983 song
= grooveshark
.songItem(id, name
, album
, artist
, coverart
)
984 grooveshark
.playSong(song
)
986 elif mode
==MODE_ARTIST
:
987 grooveshark
.artist(id)
989 elif mode
==MODE_ALBUM
:
990 grooveshark
.album(id)
992 elif mode
==MODE_PLAYLIST
:
993 grooveshark
.playlist(id, name
)
995 elif mode
==MODE_FAVORITE
:
996 grooveshark
.favorite(id)
998 elif mode
==MODE_UNFAVORITE
:
999 try: prevMode
=int(urllib
.unquote_plus(params
["prevmode"]))
1002 grooveshark
.unfavorite(id, prevMode
)
1004 elif mode
==MODE_SIMILAR_ARTISTS
:
1005 grooveshark
.similarArtists(id)
1007 elif mode
==MODE_MAKE_PLAYLIST
:
1008 grooveshark
.makePlaylist(id, name
)
1010 elif mode
==MODE_REMOVE_PLAYLIST
:
1011 grooveshark
.removePlaylist(id, name
)
1013 elif mode
==MODE_RENAME_PLAYLIST
:
1014 grooveshark
.renamePlaylist(id, name
)
1016 elif mode
==MODE_REMOVE_PLAYLIST_SONG
:
1017 try: playlistID
=urllib
.unquote_plus(params
["playlistid"])
1019 grooveshark
.removePlaylistSong(playlistID
, name
, id)
1021 elif mode
==MODE_ADD_PLAYLIST_SONG
:
1022 grooveshark
.addPlaylistSong(id)
1024 if mode
< MODE_SONG
:
1025 xbmcplugin
.endOfDirectory(int(sys
.argv
[1]))