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