Add optional 1.0 API for those with a session id.
authorstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Thu, 27 Jan 2011 15:44:11 +0000 (15:44 +0000)
committerstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Thu, 27 Jan 2011 15:44:11 +0000 (15:44 +0000)
git-svn-id: svn://svn.code.sf.net/p/xbmc-groove/code@44 2dec19e3-eb1d-4749-8193-008c8bba0994

addon.xml
changelog.txt
default.py
description.xml
methods.txt [deleted file]
resources/language/English/strings.xml
resources/lib/GrooveAPI.py [deleted file]
resources/lib/GroovesharkAPI.py
resources/settings.xml
viewapi1sessionid.py [new file with mode: 0644]

index 4b1fb11..d4ab73e 100644 (file)
--- a/addon.xml
+++ b/addon.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <addon id="plugin.audio.groove" name="Grooveshark XBMC"
-       version="0.3.0" provider-name="Stephen Denham">
+       version="0.4.0" provider-name="Stephen Denham">
        <requires>
                <import addon="xbmc.python" version="1.0" />
        </requires>
index 60fbcef..6d76714 100644 (file)
@@ -1,3 +1,7 @@
+0.4.0:
+
+Add optional 1.0 API for those with a session id.
+
 0.3.0:
 
 Get artist's albums.
index f07928a..d44a236 100644 (file)
@@ -12,8 +12,15 @@ MODE_ALBUM = 10
 MODE_ARTIST = 11
 MODE_PLAYLIST = 12
 MODE_SONG_PAGE = 13
-MODE_SONG = 14
-MODE_FAVORITE = 15
+MODE_SIMILAR_ARTISTS = 14
+MODE_SONG = 15
+MODE_FAVORITE = 16
+MODE_UNFAVORITE = 17
+MODE_MAKE_PLAYLIST = 18
+MODE_REMOVE_PLAYLIST = 19
+MODE_RENAME_PLAYLIST = 20
+MODE_REMOVE_PLAYLIST_SONG = 21
+MODE_ADD_PLAYLIST_SONG = 22
 
 ACTION_MOVE_LEFT = 1
 ACTION_MOVE_UP = 3
@@ -43,9 +50,11 @@ favoritesUrl = baseModeUrl + '?mode=' + str(MODE_FAVORITES)
 searchArtistsAlbumsName = "Search for artist's albums..."
 
 thumbDef = os.path.join(imgDir, 'default.tbn')
+listBackground = os.path.join(imgDir, 'listbackground.png')
 
 sys.path.append (libDir)
 from GroovesharkAPI import GrooveAPI
+from GroovesharkAPI import GrooveAPIv1
 
 try:
     groovesharkApi = GrooveAPI()
@@ -61,6 +70,67 @@ class _Info:
     def __init__( self, *args, **kwargs ):
         self.__dict__.update( kwargs )
 
+# Window dialog to select a grooveshark playlist        
+class GroovesharkPlaylistSelect(xbmcgui.WindowDialog):
+    
+    def __init__(self, items=[]):
+        gap = int(self.getHeight()/100)
+        w = int(self.getWidth()*0.5)
+        h = self.getHeight()-30*gap
+        rw = self.getWidth()
+        rh = self.getHeight()
+        x = rw/2 - w/2
+        y = rh/2 -h/2
+        
+        self.imgBg = xbmcgui.ControlImage(x+gap, 5*gap+y, w-2*gap, h-5*gap, listBackground)
+        self.addControl(self.imgBg)
+
+        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)
+        self.addControl(self.playlistControl)
+
+        self.lastPos = 0
+        self.isSelecting = False
+        self.selected = -1
+        listitems = []
+        for playlist in items:
+            listitems.append(xbmcgui.ListItem(playlist[0]))
+        listitems.append(xbmcgui.ListItem('New...'))
+        self.playlistControl.addItems(listitems)
+        self.setFocus(self.playlistControl)
+        self.playlistControl.selectItem(0)
+        item = self.playlistControl.getListItem(self.lastPos)
+        item.select(True)
+
+    # Highlight selected item
+    def setHighlight(self):
+        if self.isSelecting:
+            return
+        else:
+            self.isSelecting = True
+        
+        pos = self.playlistControl.getSelectedPosition()
+        if pos >= 0:
+            item = self.playlistControl.getListItem(self.lastPos)
+            item.select(False)
+            item = self.playlistControl.getListItem(pos)
+            item.select(True)
+            self.lastPos = pos
+        self.isSelecting = False
+
+    # Control - select
+    def onControl(self, control):
+        if control == self.playlistControl:
+            self.selected = self.playlistControl.getSelectedPosition()
+            self.close()
+
+    # Action - close or up/down        
+    def onAction(self, action):
+        if action == ACTION_PREVIOUS_MENU:
+            self.selected = -1
+            self.close()
+        elif action == ACTION_MOVE_UP or action == ACTION_MOVE_DOWN or action == ACTION_PAGE_UP or action == ACTION_PAGE_DOWN == 6:
+            self.setFocus(self.playlistControl)
+            self.setHighlight()
      
 class Groveshark:
     
@@ -83,6 +153,7 @@ class Groveshark:
     songspagelimit = int(settings.getSetting('songspagelimit'))
     username = settings.getSetting('username')
     password = settings.getSetting('password')
+    sessionidv1 = settings.getSetting('sessionidv1')
     userid = 0
     
     def __init__( self ):
@@ -94,7 +165,9 @@ class Groveshark:
         if os.path.isdir(artDir) == False:
             os.makedirs(artDir)
             xbmc.log("Made " + artDir)
-
+            
+        self.groovesharkApiv1 = GrooveAPIv1(self.sessionidv1)
+            
     # Top-level menu
     def categories(self):
 
@@ -184,7 +257,7 @@ class Groveshark:
                 xbmc.log("Found " + artist[0] + "...")
                 albums = groovesharkApi.getArtistAlbums(artistID, limit = self.albumsearchlimit)
                 if (len(albums) > 0):
-                    self._add_albums_directory(albums)
+                    self._add_albums_directory(albums, artistID)
                 else:
                     dialog = xbmcgui.Dialog()
                     dialog.ok('Grooveshark XBMC', 'No matching albums.')
@@ -202,7 +275,7 @@ class Groveshark:
         if (userid != 0):
             favorites = groovesharkApi.getUserFavoriteSongs()
             if (len(favorites) > 0):
-                self._add_songs_directory(favorites)
+                self._add_songs_directory(favorites, isFavorites=True)
             else:
                 dialog = xbmcgui.Dialog()
                 dialog.ok('Grooveshark XBMC', 'You have no favorites.')
@@ -243,6 +316,21 @@ class Groveshark:
         else:
             dialog = xbmcgui.Dialog()
             dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to add favorites.')
+            
+    # Remove song from favorites
+    def unfavorite(self, songid, prevMode=0):
+        userid = self._get_login(version = 1)
+        if (userid != 0):
+            xbmc.log("Unfavorite song: " + str(songid) + ', previous mode was ' + str(prevMode))
+            self.groovesharkApiv1.unfavorite(songID = songid)
+            xbmc.executebuiltin('XBMC.Notification(Grooveshark XBMC, Removed from Grooveshark favorites, 1000, ' + thumbDef + ')')
+            # Refresh to remove item from directory
+            if (int(prevMode) == MODE_FAVORITES):
+                xbmc.executebuiltin("Container.Refresh(" + favoritesUrl + ")")
+        else:
+            dialog = xbmcgui.Dialog()
+            dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to remove Grooveshark favorites.')
+            
 
     # Show selected album
     def album(self, albumid):
@@ -252,14 +340,17 @@ class Groveshark:
     # Show selected artist
     def artist(self, artistid):
         albums = groovesharkApi.getArtistAlbums(artistid, limit = self.albumsearchlimit)
-        self._add_albums_directory(albums)
+        self._add_albums_directory(albums, artistid)
     
     # Show selected playlist
-    def playlist(self, playlistid):
+    def playlist(self, playlistid, playlistname, version = 2):
         userid = self._get_login()
         if (userid != 0):
-            songs = groovesharkApi.getPlaylistSongs(playlistid)
-            self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL)
+            if version == 1:
+                songs = self.groovesharkApiv1.playlistGetSongs(playlistid)                
+            else:
+                songs = groovesharkApi.getPlaylistSongs(playlistid)
+            self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL, playlistid=playlistid, playlistname=playlistname)
         else:
             dialog = xbmcgui.Dialog()
             dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to get Grooveshark playlists.')
@@ -318,8 +409,133 @@ class Groveshark:
         return item
     
     # Next page of songs
-    def songPage(self, page, trackLabelFormat):
-        self._add_songs_directory([], trackLabelFormat, page)
+    def songPage(self, page, trackLabelFormat, playlistid = 0, playlistname = ''):
+        self._add_songs_directory([], trackLabelFormat, page, playlistid = playlistid, playlistname = playlistname)
+        
+    # Make a playlist from an album      
+    def makePlaylist(self, albumid, name):
+        userid = self._get_login(version = 1)
+        if (userid != 0):
+            re.split(' - ',name,1)
+            nameTokens = re.split(' - ',name,1) # suggested name
+            name = self._get_keyboard(default=nameTokens[0], heading="Grooveshark playlist name")
+            if name != '':
+                album = groovesharkApi.getAlbumSongs(albumid, limit = self.songsearchlimit)
+                songids = []
+                for song in album:
+                    songids.append(song[1])
+                if self.groovesharkApiv1.playlistCreateUnique(name, songids) == 0:
+                    dialog = xbmcgui.Dialog()
+                    dialog.ok('Grooveshark XBMC', 'Cannot create Grooveshark playlist ', name)
+                else:
+                    xbmc.executebuiltin('XBMC.Notification(Grooveshark XBMC, Grooveshark playlist created, 1000, ' + thumbDef + ')')
+        else:
+            dialog = xbmcgui.Dialog()
+            dialog.ok('Grooveshark XBMC', 'You must be logged in ', ' to create a Grooveshark playlist.')
+    
+    # Rename a playlist
+    def renamePlaylist(self, playlistid, name):
+        userid = self._get_login(version = 1)
+        if (userid != 0):
+            newname = self._get_keyboard(default=name, heading="Grooveshark playlist name")
+            if newname == '':
+                return
+            elif self.groovesharkApiv1.playlistRename(playlistid, newname) == 0:
+                dialog = xbmcgui.Dialog()
+                dialog.ok('Grooveshark XBMC', 'Cannot rename Grooveshark playlist ', name)
+            else:
+                # Refresh to show new item name
+                xbmc.executebuiltin("Container.Refresh")
+        else:
+            dialog = xbmcgui.Dialog()
+            dialog.ok('Grooveshark XBMC', 'You must be logged in ', ' to rename a Grooveshark playlist.')
+        
+    # Remove a playlist
+    def removePlaylist(self, playlistid, name):
+        dialog = xbmcgui.Dialog()
+        if dialog.yesno('Grooveshark XBMC', name, 'Delete this Grooveshark playlist?') == True:
+            userid = self._get_login(version = 1)
+            if (userid != 0):
+                if self.groovesharkApiv1.playlistDelete(playlistid) == 0:
+                    dialog = xbmcgui.Dialog()
+                    dialog.ok('Grooveshark XBMC', 'Cannot remove Grooveshark playlist ', name)
+                else:
+                    # Refresh to remove item from directory
+                    xbmc.executebuiltin("Container.Refresh(" + playlistsUrl + ")")
+            else:
+                dialog = xbmcgui.Dialog()
+                dialog.ok('Grooveshark XBMC', 'You must be logged in ', ' to delete a Grooveshark playlist.')
+
+    # Add song to playlist
+    def addPlaylistSong(self, songid):
+        userid = self._get_login(version = 1)
+        if (userid != 0):
+            playlists = groovesharkApi.getUserPlaylists()
+            if (len(playlists) > 0):
+                ret = 0
+                # Select the playlist
+                playlistSelect = GroovesharkPlaylistSelect(items=playlists)
+                playlistSelect.setFocus(playlistSelect.playlistControl)
+                playlistSelect.doModal()
+                i = playlistSelect.selected
+                del playlistSelect
+                if i > -1:
+                    # Add a new playlist
+                    if i >= len(playlists):
+                        name = self._get_keyboard(default='', heading="Grooveshark playlist name")
+                        if name != '':
+                            songIds = []
+                            songIds.append(songid)
+                            if self.groovesharkApiv1.playlistCreateUnique(name, songIds) == 0:
+                                dialog = xbmcgui.Dialog()
+                                dialog.ok('Grooveshark XBMC', 'Cannot create Grooveshark playlist ', name)
+                            else:
+                                xbmc.executebuiltin('XBMC.Notification(Grooveshark XBMC, Grooveshark playlist created, 1000, ' + thumbDef + ')')
+                    # Existing playlist
+                    else:
+                        playlist = playlists[i]
+                        playlistid = playlist[1]
+                        xbmc.log("Add song " + str(songid) + " to playlist " + str(playlistid))
+                        ret = self.groovesharkApiv1.playlistAddSong(playlistid, songid, 0)
+                        if ret == 0:
+                            dialog = xbmcgui.Dialog()
+                            dialog.ok('Grooveshark XBMC', 'Cannot add to playlist ')
+                        else:    
+                            xbmc.executebuiltin('XBMC.Notification(Grooveshark XBMC, Added song to Grooveshark playlist, 1000, ' + thumbDef + ')')
+            else:
+                dialog = xbmcgui.Dialog()
+                dialog.ok('Grooveshark XBMC', 'You have no Grooveshark playlists.')
+                self.categories()
+        else:
+            dialog = xbmcgui.Dialog()
+            dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to add a song to a Grooveshark playlist.')
+
+    # Remove song from playlist
+    def removePlaylistSong(self, playlistid, playlistname, songpos):
+        dialog = xbmcgui.Dialog(version = 1)
+        if dialog.yesno('Grooveshark XBMC', 'Delete this song from the Grooveshark playlist?') == True:
+            userid = self._get_login(version = 1)
+            if (userid != 0):
+                if self.groovesharkApiv1.playlistDeleteSong(playlistid, songpos) == 0:
+                    dialog = xbmcgui.Dialog()
+                    dialog.ok('Grooveshark XBMC', 'Failed to remove', 'song from Grooveshark playlist.')
+                else:
+                    # Refresh to remove item from directory
+                    xbmc.executebuiltin('XBMC.Notification(Grooveshark XBMC, Removed song from Grooveshark playlist, 1000, ' + thumbDef + ')')
+                    xbmc.executebuiltin("Container.Update(" + playlistUrl + "&id="+str(playlistid) + "&name=" + playlistname + "&version=1)")
+            else:
+                dialog = xbmcgui.Dialog()
+                dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to delete a song from a Grooveshark playlist.')
+      
+    # Find similar artists to searched artist
+    def similarArtists(self, artistId):
+        similar = self.groovesharkApiv1.artistGetSimilar(artistId, limit = self.artistsearchlimit)
+        if (len(similar) > 0):
+            self._add_artists_directory(similar)
+        else:
+            dialog = xbmcgui.Dialog()
+            dialog.ok('Grooveshark XBMC', 'No similar artists.')
+            self.categories()
         
     # Get keyboard input
     def _get_keyboard(self, default="", heading="", hidden=False):
@@ -330,14 +546,17 @@ class Groveshark:
         return ''
     
     # Login to grooveshark
-    def _get_login(self):
+    def _get_login(self, version = 2):
         if (self.username == "" or self.password == ""):
             dialog = xbmcgui.Dialog()
             dialog.ok('Grooveshark XBMC', 'Unable to login.', 'Check username and password in settings.')
             return 0
         else:
             if self.userid == 0:
-                uid = groovesharkApi.login(self.username, self.password)
+                if version == 1:
+                    uid = self.groovesharkApiv1.login(self.username, self.password)
+                else:
+                    uid = groovesharkApi.login(self.username, self.password)
             if (uid != 0):
                 return uid
             else:
@@ -369,7 +588,7 @@ class Groveshark:
             return thumbDef
     
     # Add songs to directory
-    def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, page=0):
+    def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, page=0, playlistid=0, playlistname='', isFavorites=False):
 
         totalSongs = len(songs)
         page = int(page)
@@ -391,6 +610,7 @@ class Groveshark:
                 end = start + self.songspagelimit
                 songs = songs[start:end]
         
+        id = 0
         for song in songs:
             item = self._get_song_item(song, trackLabelFormat)
             coverart = item.getProperty('coverart')
@@ -403,21 +623,34 @@ class Groveshark:
             +"&artist="+urllib.quote_plus(songartist) \
             +"&coverart="+urllib.quote_plus(coverart)
             fav=sys.argv[0]+"?mode="+str(MODE_FAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)
+            unfav=sys.argv[0]+"?mode="+str(MODE_UNFAVORITE)+"&name="+urllib.quote_plus(songname)+"&id="+str(songid)+"&prevmode="
             menuItems = []
-            menuItems.append(("Grooveshark favorite", "XBMC.RunPlugin("+fav+")"))
+            if isFavorites == True:
+                unfav = unfav +str(MODE_FAVORITES)
+            else:
+                menuItems.append(("Grooveshark favorite", "XBMC.RunPlugin("+fav+")"))
+            if self.sessionidv1 != '':
+                menuItems.append(("Not Grooveshark favorite", "XBMC.RunPlugin("+unfav+")"))
+                if playlistid > 0:
+                    rmplaylstsong=sys.argv[0]+"?playlistid="+str(playlistid)+"&id="+str(id+1)+"&mode="+str(MODE_REMOVE_PLAYLIST_SONG)+"&name="+playlistname
+                    menuItems.append(("Remove from Grooveshark playlist", "XBMC.RunPlugin("+rmplaylstsong+")"))
+                else:
+                    addplaylstsong=sys.argv[0]+"?id="+str(songid)+"&mode="+str(MODE_ADD_PLAYLIST_SONG)
+                    menuItems.append(("Add to Grooveshark playlist", "XBMC.RunPlugin("+addplaylstsong+")"))
             item.addContextMenuItems(menuItems, replaceItems=False)
             xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False, totalItems=len(songs))
+            id = id + 1
 
         page = page + 1
         if totalSongs > page * self.songspagelimit:
-            u=sys.argv[0]+"?mode="+str(MODE_SONG_PAGE)+"&id=0"+"&page="+str(page)+"&label="+str(trackLabelFormat)
+            u=sys.argv[0]+"?mode="+str(MODE_SONG_PAGE)+"&id=playlistid"+"&page="+str(page)+"&label="+str(trackLabelFormat)+"&name="+playlistname
             self._add_dir('More songs...', u, MODE_SONG_PAGE, self.songImg, 0, totalSongs - (page * self.songspagelimit))
 
         xbmcplugin.setContent(self._handle, 'songs')
         xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
     
     # Add albums to directory
-    def _add_albums_directory(self, albums):
+    def _add_albums_directory(self, albums, artistid=0):
         n = len(albums)
         xbmc.log("Found " + str(n) + " albums...")
         i = 0
@@ -429,6 +662,8 @@ class Groveshark:
             albumImage = self._get_icon(album[4], 'album-' + str(albumID))
             self._add_dir(albumName + " - " + albumArtistName, '', MODE_ALBUM, albumImage, albumID, n)
             i = i + 1
+        if artistid > 0 and self.sessionidv1 != '':
+            self._add_dir('Similar artists...', '', MODE_SIMILAR_ARTISTS, self.artistImg, artistid)
         xbmcplugin.setContent(self._handle, 'albums')
         xbmcplugin.addSortMethod(self._handle, xbmcplugin.SORT_METHOD_ALBUM_IGNORE_THE)
         xbmcplugin.setPluginFanart(int(sys.argv[1]), self.fanImg)
@@ -465,12 +700,27 @@ class Groveshark:
       
     # Add whatever directory
     def _add_dir(self, name, url, mode, iconimage, id, items=1):
+
         if url == '':
             u=sys.argv[0]+"?mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
         else:
             u = url
         dir=xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage)
         dir.setInfo( type="Music", infoLabels={ "title": name } )
+        
+        # Custom menu items
+        if self.sessionidv1 != '':
+            menuItems = []
+            if mode == MODE_ALBUM:
+                mkplaylst=sys.argv[0]+"?mode="+str(MODE_MAKE_PLAYLIST)+"&name="+name+"&id="+str(id)
+                menuItems.append(("Make Grooveshark playlist", "XBMC.RunPlugin("+mkplaylst+")"))
+            if mode == MODE_PLAYLIST:
+                rmplaylst=sys.argv[0]+"?mode="+str(MODE_REMOVE_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
+                menuItems.append(("Delete Grooveshark playlist", "XBMC.RunPlugin("+rmplaylst+")"))
+                mvplaylst=sys.argv[0]+"?mode="+str(MODE_RENAME_PLAYLIST)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
+                menuItems.append(("Rename Grooveshark playlist", "XBMC.RunPlugin("+mvplaylst+")"))
+            dir.addContextMenuItems(menuItems, replaceItems=False)
+        
         return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=dir,isFolder=True, totalItems=items)
     
     def _getSavedSongs(self):
@@ -497,8 +747,6 @@ class Groveshark:
             xbmc.log("An error occurred saving songs")
             pass
     
-
-
 # Parse URL parameters
 def get_params():
     param=[]
@@ -528,6 +776,9 @@ except: pass
 id=0
 try: id=int(params["id"])
 except: pass
+name = None
+try: name=urllib.unquote_plus(params["name"])
+except: pass
 
 # Call function for URL
 if mode==None:
@@ -543,10 +794,6 @@ elif mode==MODE_SEARCH_ARTISTS:
     grooveshark.searchArtists()
     
 elif mode==MODE_SEARCH_ARTISTS_ALBUMS:
-    try: name=urllib.unquote_plus(params["name"])
-    except: 
-        name = None
-        pass
     grooveshark.searchArtistsAlbums(name)
     
 elif mode==MODE_SEARCH_PLAYLISTS:
@@ -569,11 +816,9 @@ elif mode==MODE_SONG_PAGE:
     except: pass
     try: label=urllib.unquote_plus(params["label"])
     except: pass
-    grooveshark.songPage(page, label)
+    grooveshark.songPage(page, label, id, name)
 
 elif mode==MODE_SONG:
-    try: name=urllib.unquote_plus(params["name"])
-    except: pass
     try: album=urllib.unquote_plus(params["album"])
     except: pass
     try: artist=urllib.unquote_plus(params["artist"])
@@ -590,10 +835,39 @@ elif mode==MODE_ALBUM:
     grooveshark.album(id)
     
 elif mode==MODE_PLAYLIST:
-    grooveshark.playlist(id)
+    version = 2
+    try: version=urllib.unquote_plus(params["version"])
+    except: pass
+    grooveshark.playlist(id, name, version)
     
 elif mode==MODE_FAVORITE:
     grooveshark.favorite(id)
     
+elif mode==MODE_UNFAVORITE:
+    try: prevMode=int(urllib.unquote_plus(params["prevmode"]))
+    except:
+        prevMode = 0
+    grooveshark.unfavorite(id, prevMode)
+
+elif mode==MODE_SIMILAR_ARTISTS:
+    grooveshark.similarArtists(id)
+
+elif mode==MODE_MAKE_PLAYLIST:
+    grooveshark.makePlaylist(id, name)
+    
+elif mode==MODE_REMOVE_PLAYLIST:
+    grooveshark.removePlaylist(id, name)    
+
+elif mode==MODE_RENAME_PLAYLIST:
+    grooveshark.renamePlaylist(id, name)    
+
+elif mode==MODE_REMOVE_PLAYLIST_SONG:
+    try: playlistID=urllib.unquote_plus(params["playlistid"])
+    except: pass
+    grooveshark.removePlaylistSong(playlistID, name, id)
+
+elif mode==MODE_ADD_PLAYLIST_SONG:
+    grooveshark.addPlaylistSong(id)        
+    
 if mode < MODE_SONG:
     xbmcplugin.endOfDirectory(int(sys.argv[1]))
index 6503b7d..f34ea24 100644 (file)
@@ -18,7 +18,7 @@
        <title>Grooveshark XBMC.</title>
 
        <!-- (required) Major.minor.build -->
-       <version>0.3.0</version>
+       <version>0.4.0</version>
 
        <!--
                (required) author name & email. at least one author name is required
diff --git a/methods.txt b/methods.txt
deleted file mode 100644 (file)
index a3abbb2..0000000
+++ /dev/null
@@ -1,302 +0,0 @@
-   { METHOD: u'autoplayStartWithArtistIDs',
-    u'parameters': [u'artistIDs'],
-    u'sessionRequired': True},
-   { METHOD: u'autoplayGetNextSongEx',
-    u'parameters': [u'seedArtists',
-                    u'frowns',
-                    u'songIDsAlreadySeen',
-                    u'recentArtists',
-                    u'secondaryArtistWeightModifier',
-                    u'seedArtistWeightRange',
-                    u'weightModifierRange',
-                    u'minDuration',
-                    u'maxDuration'],
-    u'sessionRequired': True},
-   { METHOD: u'autoplayGetArtistsForTag',
-    u'parameters': [u'tagID'],
-    u'sessionRequired': True},
-   { METHOD: u'albumAbout',
-    u'parameters': [u'albumID'],
-    u'sessionRequired': True},
-   { METHOD: u'albumGetSongs',
-    u'parameters': [u'albumID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'artistAbout',
-    u'parameters': [u'artistID'],
-    u'sessionRequired': True},
-   { METHOD: u'artistGetAlbums',
-    u'parameters': [u'artistID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'artistGetUnverifiedAlbums',
-    u'parameters': [u'artistID', u'limit'],
-    u'sessionRequired': True},
-   { METHOD: u'artistGetVerifiedAlbums',
-    u'parameters': [u'artistID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'artistGetSimilar',
-    u'parameters': [u'artistID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'artistGetSongs',
-    u'parameters': [u'artistID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistAbout',
-    u'parameters': [u'playlistID'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistAddSong',
-    u'parameters': [u'playlistID',
-                    u'songID',
-                    u'position'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistRemoveSong',
-    u'parameters': [u'playlistID', u'position'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistGetSongs',
-    u'parameters': [u'playlistID',
-                    u'limit',
-                    u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistGetSongsEx',
-    u'parameters': [u'playlistID'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistSubscribeUser',
-    u'parameters': [u'playlistID'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistMoveSong',
-    u'parameters': [u'playlistID',
-                    u'position',
-                    u'newPosition'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistReplace',
-    u'parameters': [u'playlistID', u'songIDs'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistRename',
-    u'parameters': [u'playlistID', u'name'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistDelete',
-    u'parameters': [u'playlistID'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistCreate',
-    u'parameters': [u'name', u'about'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistCreateUnique',
-    u'parameters': [u'name', u'songIDs'],
-    u'sessionRequired': True},
-   { METHOD: u'playlistClearSongs',
-    u'parameters': [u'playlistID'],
-    u'sessionRequired': True},
-   { METHOD: u'popularGetSongs',
-    u'parameters': [u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'popularGetSongsEx',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'searchAlbums',
-    u'parameters': [u'query', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'searchArtists',
-    u'parameters': [u'query', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'searchPlaylists',
-    u'parameters': [u'query', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'searchSongs',
-    u'parameters': [u'query', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'searchSongsUnfiltered',
-    u'parameters': [u'query', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionStart',
-    u'parameters': [u'apiKey', u'mobileID'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionGet',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'sessionLogin',
-    u'parameters': [u'username', u'password'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionLoginEx',
-    u'parameters': [u'username', u'token'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionLoginExt',
-    u'parameters': [u'username', u'token'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionLoginExte',
-    u'parameters': [u'username',
-                    u'token',
-                    u'mobileID'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionGetUserInfo',
-    u'parameters': [u'sessionID'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionLogout',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'sessionGetUserID',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'sessionDestroy',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'songGetStreamUrl',
-    u'parameters': [u'songID'],
-    u'sessionRequired': True},
-   { METHOD: u'songGetStreamUrlEx',
-    u'parameters': [u'songID', u'lowBitrate'],
-    u'sessionRequired': True},
-   { METHOD: u'songGetStreamUrlExt',
-    u'parameters': [u'songID',
-                    u'mobileID',
-                    u'country',
-                    u'lowBitrate',
-                    u'prefetch'],
-    u'sessionRequired': True},
-   { METHOD: u'songSetPlaybackReached30Seconds',
-    u'parameters': [u'streamKey', u'streamServerID'],
-    u'sessionRequired': True},
-   { METHOD: u'songMarkStreamKeyOver30Seconds',
-    u'parameters': [u'songID',
-                    u'mobileID',
-                    u'streamKey',
-                    u'streamServerID'],
-    u'sessionRequired': True},
-   { METHOD: u'songMarkComplete',
-    u'parameters': [u'songID',
-                    u'streamKey',
-                    u'streamServerID'],
-    u'sessionRequired': True},
-   { METHOD: u'songAbout',
-    u'parameters': [u'songID'],
-    u'sessionRequired': True},
-   { METHOD: u'songGetInfo',
-    u'parameters': [u'songID'],
-    u'sessionRequired': True},
-   { METHOD: u'songGetSimilar',
-    u'parameters': [u'songID', u'limit', u'page'],
-    u'sessionRequired': True},
-   { METHOD: u'songFavorite',
-    u'parameters': [u'songID'],
-    u'sessionRequired': True},
-   { METHOD: u'songUnfavorite',
-    u'parameters': [u'songID'],
-    u'sessionRequired': True},
-   { METHOD: u'userGetPlaylists',
-    u'parameters': [u'userID',
-                    u'limit',
-                    u'page',
-                    u'offset'],
-    u'sessionRequired': True},
-   { METHOD: u'userGetPlaylistsEx',
-    u'parameters': [u'userID'],
-    u'sessionRequired': True},
-   { METHOD: u'userGetPlaylistsModifiedTime',
-    u'parameters': [u'userID'],
-    u'sessionRequired': True},
-   { METHOD: u'userGetSubscribedPlaylists',
-    u'parameters': [u'userID'],
-    u'sessionRequired': True},
-   { METHOD: u'userGetFavoriteSongs',
-    u'parameters': [u'userID',
-                    u'limit',
-                    u'page',
-                    u'offset'],
-    u'sessionRequired': True},
-   { METHOD: u'tinysongCreate',
-    u'parameters': [u'songID',
-                    u'query',
-                    u'useFirstResult'],
-    u'sessionRequired': True},
-   { METHOD: u'tinysongGetExpandedUrl',
-    u'parameters': [u'tinySongUrl'],
-    u'sessionRequired': True},
-   { METHOD: u'servicePing',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkMarkSongDownloadedFromServer',
-    u'parameters': [u'songID',
-                    u'streamKey',
-                    u'streamServerID'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRegisterMobile',
-    u'parameters': [u'hash',
-                    u'phoneType',
-                    u'phoneNumber',
-                    u'mnc',
-                    u'mcc',
-                    u'simSerial'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRegisterMobileEx',
-    u'parameters': [u'uuid',
-                    u'mcc',
-                    u'mnc',
-                    u'manufacturer',
-                    u'model',
-                    u'osVersion'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRegisterMobileExt',
-    u'parameters': [u'uuid',
-                    u'mcc',
-                    u'mnc',
-                    u'manufacturer',
-                    u'model',
-                    u'osVersion',
-                    u'phoneType'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetMobileStatusEx',
-    u'parameters': [u'mobileID'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetMobileIDByHash',
-    u'parameters': [u'hash'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetSongFromToken',
-    u'parameters': [u'token', u'country'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetTokenForSongID',
-    u'parameters': [u'songID', u'country'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRegisterUser',
-    u'parameters': [u'username',
-                    u'password',
-                    u'firstName',
-                    u'lastName',
-                    u'emailAddress'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkMarkSongsPlayedOffline',
-    u'parameters': [u'songIDs'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRecordOfflineSongPlays',
-    u'parameters': [u'offlinePlays'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkRecordOfflineSongPlaysEx',
-    u'parameters': [u'mobileID', u'offlinePlays'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetUserPlaylistsModifiedSince',
-    u'parameters': [u'userID', u'time'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetCountry',
-    u'parameters': [],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetCountryFromISO',
-    u'parameters': [u'iso'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetCountryFromIP',
-    u'parameters': [u'ip'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkStartMobileTrial',
-    u'parameters': [u'mobileID'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkStartMobileTrialEx',
-    u'parameters': [u'mobileID'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkSearchProductByUPC',
-    u'parameters': [u'upc'],
-    u'sessionRequired': True},
-   { METHOD: u'tinysongGetSongFromToken',
-    u'parameters': [u'token'],
-    u'sessionRequired': True},
-   { METHOD: u'sessionCheck',
-    u'parameters': [u'sessionID'],
-    u'sessionRequired': True},
-   { METHOD: u'groovesharkGetArtistIDsFromArtistNames',
-    u'parameters': [u'artistNames'],
-    u'sessionRequired': True}]}}
-
index ca757da..9e6d820 100644 (file)
@@ -6,4 +6,5 @@
        <string id="30003">Album search limit</string>
        <string id="30004">Artist search limit</string>
        <string id="30005">Number of songs per page</string>
+       <string id="30006">API 1.0 session id</string>
 </strings>
\ No newline at end of file
diff --git a/resources/lib/GrooveAPI.py b/resources/lib/GrooveAPI.py
deleted file mode 100644 (file)
index 9d1cf23..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-import urllib2, md5, os, traceback, sys, pickle, socket, xbmc
-from operator import itemgetter
-
-class LoginTokensExceededError(Exception):
-       def __init__(self):
-               self.value = 'You have created to many tokens. Only 12 are allowed'
-       def __str__(self):
-               return repr(self.value)
-               
-class LoginUnknownError(Exception):
-       def __init__(self):
-               self.value = 'Unable to get a new session ID. Wait a few minutes and try again'
-       def __str__(self):
-               return repr(self.value)
-
-class SessionIDTryAgainError(Exception):
-       def __init__(self):
-               self.value = 'Unable to get a new session ID. Wait a few minutes and try again'
-       def __str__(self):
-               return repr(self.value)
-
-class GrooveAPI:
-       def __init__(self, enableDebug = False, isXbox = False):
-               import simplejson
-               self.simplejson = simplejson
-               timeout = 40
-               socket.setdefaulttimeout(timeout)
-               self.enableDebug = enableDebug
-               self.loggedIn = 0
-               self.userId = 0
-               self.removeDuplicates = False
-
-               self.radioRecentSongs = []
-               self.radioRecentArtists = []
-               self.radioEnabled = False
-
-               self.dataDir = 'addon_data'
-               self.confDir = xbmc.translatePath(os.path.join('special://masterprofile/' + self.dataDir, os.path.basename(os.getcwd())))
-               self.sessionID = self.getSavedSession()
-               self.debug('Saved sessionID: ' + self.sessionID)
-               #self.sessionID = self.getSessionFromAPI()
-               #self.debug('API sessionID: ' + self.sessionID)
-               if self.sessionID == '':
-                       self.sessionID = self.startSession()
-                       self.debug('Start() sessionID: ' + self.sessionID)
-                       if self.sessionID == '':
-                               self.debug('Could not get a sessionID. Try again in a few minutes')
-                               raise SessionIDTryAgainError()
-                       else:
-                               self.saveSession()
-               
-               self.debug('sessionID: ' + self.sessionID)
-
-       def __del__(self):
-               try:
-                       if self.loggedIn == 1:
-                               self.logout()
-               except:
-                       pass
-                       
-       def debug(self, msg):
-               if self.enableDebug == True:
-                       print msg
-
-       def setRemoveDuplicates(self, enable):
-               if enable == True or enable == 'true' or enable == 'True':
-                       self.removeDuplicates = True
-               else:
-                       self.removeDuplicates = False
-                       
-       def getSavedSession(self):
-               sessionID = ''
-               path = os.path.join(self.confDir, 'session', 'session.txt')
-
-               try:
-                       f = open(path, 'rb')
-                       sessionID = pickle.load(f)
-                       f.close()
-               except:
-                       sessionID = ''
-                       pass            
-               
-               return sessionID
-
-       def saveSession(self):                  
-               try:
-                       dir = os.path.join(self.confDir, 'session')
-                       # Create the 'data' directory if it doesn't exist.
-                       if not os.path.exists(dir):
-                               os.makedirs(dir)
-                       path = os.path.join(dir, 'session.txt')
-                       f = open(path, 'wb')
-                       pickle.dump(self.sessionID, f, protocol=pickle.HIGHEST_PROTOCOL)
-                       f.close()
-               except IOError, e:
-                       print 'There was an error while saving the session pickle (%s)' % e
-                       pass
-               except:
-                       print "An unknown error occured during save session: " + str(sys.exc_info()[0])
-                       pass
-                       
-       def saveSettings(self):                 
-               try:
-                       dir = os.path.join(self.confDir, 'data')
-                       # Create the 'data' directory if it doesn't exist.
-                       if not os.path.exists(dir):
-                               os.makedirs(dir)
-                       path = os.path.join(dir, 'settings1.txt')
-                       f = open(path, 'wb')
-                       pickle.dump(self.settings, f, protocol=pickle.HIGHEST_PROTOCOL)
-                       f.close()
-               except IOError, e:
-                       print 'There was an error while saving the settings pickle (%s)' % e
-                       pass
-               except:
-                       print "An unknown error occured during save settings\n"
-                       pass
-
-       def callRemote(self, method, params={}):
-               data = {'header': {'sessionID': self.sessionID}, 'method': method, 'parameters': params}
-               data = self.simplejson.dumps(data)
-               req = urllib2.Request("http://api.grooveshark.com/ws/1.0/?json")
-               req.add_header('Host', 'api.grooveshark.com')
-               req.add_header('Content-type', 'text/json')
-               req.add_header('Content-length', str(len(data)))
-               req.add_data(data)
-               response = urllib2.urlopen(req)
-               result = response.read()
-               response.close()
-               try:
-                       result = self.simplejson.loads(result)
-                       if 'fault' in result:
-                               self.debug(result)
-                               if result['fault']['code'] == 8: #Session ID has expired. Get a new and try again if possible.
-                                       self.debug(result['fault']['message'])
-                                       self.sessionID = self.startSession()
-                                       if self.sessionID != '':
-                                               self.saveSession()
-                                               return self.callRemote(method, params)
-                                       else:
-                                               self.debug('GrooveShark: SessionID expired, but unable to get new')
-                                               return []
-                       return result
-               except:
-                       return []
-
-       def startSession(self):
-               try:
-                       response = urllib2.urlopen("http://www.moovida.com/services/grooveshark/session_start")
-                       result = response.read()
-                       result = self.simplejson.loads(result)
-                       response.close()
-               except:
-                       return ''
-               
-               if 'fault' in result:
-                       return ''
-               else:
-                       return result['result']['sessionID']
-
-       def sessionDestroy(self):
-               return self.callRemote("session.destroy")
-                       
-       def getSessionFromAPI(self):
-               result = self.callRemote("session.get")
-               if 'fault' in result:
-                       return ''
-               else:
-                       return result['header']['sessionID']                                                                                            
-
-       def getStreamURL(self, songID):
-               result = self.callRemote("song.getStreamUrlEx", {"songID": songID})
-               if 'result' in result:
-                       return result['result']['url']
-               else:
-                       return ''
-       
-       def createUserAuthToken(self, username, password):
-               hashpass = md5.new(password).hexdigest()
-               hashpass = username + hashpass
-               hashpass = md5.new(hashpass).hexdigest()
-               result = self.callRemote("session.createUserAuthToken", {"username": username, "hashpass": hashpass})
-               if 'result' in result:
-                       return result['result']['token'], result['result']['userID']
-               elif 'fault' in result:
-                       if result['fault']['code'] == 256:
-                               return -1 # Exceeded the number of allowed tokens. Should not happen
-                       else:
-                               return -2 # Unknown error
-               else:
-                       return -2 # Unknown error
-       
-       def destroyUserAuthToken(self, token):
-               self.callRemote("session.destroyAuthToken", {"token": token})
-               
-       def loginViaAuthToken(self, token):
-               result = self.callRemote("session.loginViaAuthToken", {"token": token})
-               self.destroyUserAuthToken(token)
-               if 'result' in result:
-                       self.userID = result['result']['userID']
-                       return result['result']['userID']
-               else:
-                       return 0
-       
-       def login(self, username, password):
-               if self.loggedIn == 1:
-                       return self.userId
-               result = self.createUserAuthToken(username, password)
-               if result == -1:
-                       raise LoginTokensExceededError()
-               elif result == -2:
-                       raise LoginUnknownError()
-               else:
-                       self.token = result[0]
-                       self.debug('Token:' + self.token)
-                       self.userId = self.loginViaAuthToken(self.token)
-                       if self.userId == 0:
-                               raise LoginUnknownError()
-                       else:
-                               self.loggedIn = 1
-                               return self.userId
-
-                       
-       def loginExt(self, username, password):
-               if self.loggedIn == 1:
-                       return self.userId
-               token = md5.new(username.lower() + md5.new(password).hexdigest()).hexdigest()
-               result = self.callRemote("session.loginExt", {"username": username, "token": token})
-               if 'result' in result:
-                       if 'userID' in result['result']:
-                               self.loggedIn = 1
-                               self.userId = result['result']['userID']
-                               return result['result']['userID'] 
-               else:
-                       return 0
-                       
-                               
-       def loginBasic(self, username, password):
-               if self.loggedIn == 1:
-                       return self.userId
-               result = self.callRemote("session.login", {"username": username, "password": password})
-               if 'result' in result:
-                       if 'userID' in result['result']:
-                               self.loggedIn = 1
-                               self.userId = result['result']['userID']
-                               return result['result']['userID'] 
-               else:
-                       return 0
-
-       def loggedInStatus(self):
-               return self.loggedIn
-       
-       def logout(self):
-               self.callRemote("session.logout", {})
-               self.loggedIn = 0
-               
-       def getSongInfo(self, songID):
-               return self.callRemote("song.about", {"songID": songID})['result']['song']
-       
-       def userGetFavoriteSongs(self, userID):
-               result = self.callRemote("user.getFavoriteSongs", {"userID": userID})
-               list = self.parseSongs(result)
-               return list
-       
-       def userGetPlaylists(self, limit=25):
-               if self.loggedIn == 1:
-                       result = self.callRemote("user.getPlaylists", {"userID": self.userId, "limit": limit})
-                       if 'result' in result:
-                               playlists = result['result']['playlists']
-                       else:
-                               return []
-                       i = 0
-                       list = []
-                       while(i < len(playlists)):
-                               p = playlists[i]
-                               list.append([p['playlistName'].encode('ascii', 'ignore'), p['playlistID']])
-                               i = i + 1       
-                       return sorted(list, key=itemgetter(0))
-               else:
-                       return []
-
-       def playlistCreate(self, name, about):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.create", {"name": name, "about": about})
-                       if 'result' in result:
-                               return result['result']['playlistID']
-                       else:
-                               return 0
-               else:
-                       return 0
-
-       def playlistCreateUnique(self, name, songIds):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.createunique", {"name": name, "songIDs": songIds})
-                       if 'result' in result:
-                               return result['result']['playlistID']
-                       else:
-                               return 0
-               else:
-                       return 0
-                       
-       def playlistGetSongs(self, playlistId, limit=25):
-               result = self.callRemote("playlist.getSongs", {"playlistID": playlistId})
-               list = self.parseSongs(result)
-               return list
-                       
-       def playlistDelete(self, playlistId):
-               if self.loggedIn == 1:
-                       result =  self.callRemote("playlist.delete", {"playlistID": playlistId})
-                       if 'fault' in result:
-                               return 0
-                       else:
-                               return 1
-               else:
-                       return 0
-
-       def playlistRename(self, playlistId, name):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.rename", {"playlistID": playlistId, "name": name})
-                       if 'fault' in result:
-                               return 0
-                       else:
-                               return 1
-               else:
-                       return 0
-
-       def playlistClearSongs(self, playlistId):
-               if self.loggedIn == 1:
-                       return self.callRemote("playlist.clearSongs", {"playlistID": playlistId})
-
-       def playlistAddSong(self, playlistId, songId, position):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.addSong", {"playlistID": playlistId, "songID": songId, "position": position})
-                       if 'fault' in result:
-                               return 0
-                       else:
-                               return 1
-               else:
-                       return 0
-               
-       def playlistDeleteSong(self, playlistId, position):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.removeSong", {"playlistID": playlistId, "position": position})
-                       if 'fault' in result:
-                               return 0
-                       else:
-                               return 1
-               else:
-                       return 0
-                       
-       def playlistReplace(self, playlistId, songIds):
-               if self.loggedIn == 1:
-                       result = self.callRemote("playlist.replace", {"playlistID": playlistId, "songIDs": songIds})
-                       if 'fault' in result:
-                               return 0
-                       else:
-                               return 1
-               else:
-                       return 0
-
-       def radioStartArtists(self):
-               radio = self.getSavedRadio()
-               if radio == None:
-                       return False
-               result = self.callRemote("autoplay.startWithArtistIDs", {"artistIDs": radio['seedArtists']})
-               if 'fault' in result:
-                       print "Cannot autoplay artists"
-                       self.radioEnabled = False
-               else:
-                       self.radioEnabled = True
-               return self.radioEnabled
-
-       def radioStartSongs(self):
-               radio = self.getSavedRadio()
-               if radio == None:
-                       return False
-               result = self.callRemote("autoplay.start", {"songIDs": radio['seedSongs']})
-               if 'fault' in result:
-                       print "Cannot autoplay songs"
-                       self.radioEnabled = False
-               else:
-                       self.radioEnabled = True
-               return self.radioEnabled
-       
-       def radioNextSong(self):
-               radio = self.getSavedRadio()
-               if radio == None:
-                       return None
-               else:
-                       result = self.callRemote("autoplay.getNextSongEx", {"seedArtists": radio['seedArtists'], "frowns": radio['frowns'], "songIDsAlreadySeen": self.radioRecentSongs, "recentArtists": self.radioRecentArtists})
-                       if 'fault' in result:
-                               return []
-                       else:
-                               song = self.parseSongs(result)
-                               self.radioRecentSongs.append(song[0][1])
-                               self.radioRecentArtists.append(song[0][7])
-                               return song
-
-       def radioFrown(self, songId = None):
-               radio = self.getSavedRadio()
-               if radio != None and songId != None:
-                       try:
-                               radio['frowns'].remove(songId)
-                       except: pass
-                       radio['frowns'].append(songId)
-                       return self.saveRadio(radio = radio)
-               else:
-                       return False
-
-       def radioArtist(self, artistId = None):
-               radio = self.getSavedRadio()
-               if radio != None and artistId != None:
-                       try:
-                               radio['seedArtists'].remove(artistId)
-                       except: pass
-                       radio['seedArtists'].append(artistId)
-                       print "Saved radio"
-                       return self.saveRadio(radio = radio)
-               else:
-                       print "Failed to get radio"
-                       return False
-
-       def radioSong(self, songId = None):
-               radio = self.getSavedRadio()
-               if radio != None and songId != None:
-                       try:
-                               radio['seedSongs'].remove(songId)
-                       except: pass
-                       radio['seedSongs'].append(songId)
-                       print "Saved radio"
-                       return self.saveRadio(radio = radio)
-               else:
-                       print "Failed to get radio"
-                       return False
-
-       def radioTurnedOn(self):
-               return self.radioEnabled
-
-       def getSavedRadio(self):
-               path = os.path.join(self.confDir, 'radio', 'radio.dmp')
-               try:
-                       f = open(path, 'rb')
-                       radio = pickle.load(f)
-                       f.close()
-               except:
-                       print "Failed to open " + path
-                       radio = {}
-                       radio['seedSongs'] = []
-                       radio['seedArtists'] = []
-                       radio['frowns'] = []
-                       if self.saveRadio(radio) == False:
-                               return None
-               return radio
-
-       def saveRadio(self, radio): #blaher
-               if radio == {}:
-                       print 'Invalid radio'
-                       return False
-               try:
-                       dir = os.path.join(self.confDir, 'radio')
-                       # Create the 'data' directory if it doesn't exist.
-                       if not os.path.exists(dir):
-                               os.mkdir(dir)
-                       path = os.path.join(dir, 'radio.dmp')
-                       f = open(path, 'wb')
-                       pickle.dump(radio, f, protocol=pickle.HIGHEST_PROTOCOL)
-                       f.close()
-                       return True
-               except IOError, e:
-                       print 'There was an error while saving the radio pickle (%s)' % e
-                       return False
-               except:
-                       print "An unknown error occurred during save radio: " + str(sys.exc_info()[0])
-                       return False
-
-       def favoriteSong(self, songID):
-               return self.callRemote("song.favorite", {"songID": songID})
-
-       def unfavoriteSong(self, songID):
-               return self.callRemote("song.unfavorite", {"songID": songID})
-               
-       def getMethods(self):
-               return self.callRemote("service.getMethods")
-
-       def searchSongsExactMatch(self, songName, artistName, albumName):
-               result = self.callRemote("search.songExactMatch", {"songName": songName, "artistName": artistName, "albumName": albumName})
-               list = self.parseSongs(result)
-               return list
-
-       def searchSongs(self, query, limit, page=0, sortKey=6):
-               result = self.callRemote("search.songs", {"query": query, "limit": limit, "page:": page, "streamableOnly": 1})
-               list = self.parseSongs(result)
-               return list
-               #return sorted(list, key=itemgetter(sortKey))
-
-       def searchArtists(self, query, limit, sortKey=0):
-               result = self.callRemote("search.artists", {"query": query, "limit": limit, "streamableOnly": 1})
-               list = self.parseArtists(result)
-               return list
-               #return sorted(list, key=itemgetter(sortKey))
-
-       def searchAlbums(self, query, limit, sortKey=2):
-               result = self.callRemote("search.albums", {"query": query, "limit": limit, "streamableOnly": 1})
-               list = self.parseAlbums(result)
-               return list
-               #return sorted(list, key=itemgetter(sortKey))
-
-       def searchPlaylists(self, query, limit):
-               result = self.callRemote("search.playlists", {"query": query, "limit": limit, "streamableOnly": 1})
-               list = self.parsePlaylists(result)
-               return list
-
-       def popularGetSongs(self, limit):
-               result = self.callRemote("popular.getSongs", {"limit": limit})
-               list = self.parseSongs(result)
-               return list
-               
-       def popularGetArtists(self, limit):
-               result = self.callRemote("popular.getArtists", {"limit": limit})
-               list = self.parseArtists(result)
-               return list
-
-       def popularGetAlbums(self, limit):
-               result = self.callRemote("popular.getAlbums", {"limit": limit})
-               list = self.parseAlbums(result)
-               return list
-               
-       def artistAbout(self, artistId):
-               result = self.callRemote("artist.about", {"artistID": artistId})
-               return result
-               
-       def artistGetAlbums(self, artistId, limit, sortKey=2):
-               result = self.callRemote("artist.getAlbums", {"artistID": artistId, "limit": limit})
-               list = self.parseAlbums(result)
-               return list
-               #return sorted(list, key=itemgetter(sortKey))
-
-       def artistGetVerifiedAlbums(self, artistId, limit):
-               result = self.callRemote("artist.getVerifiedAlbums", {"artistID": artistId, "limit": limit})
-               list = self.parseSongs(result)
-               return list
-
-       def albumGetSongs(self, albumId, limit):
-               result = self.callRemote("album.getSongs", {"albumID": albumId, "limit": limit})
-               list = self.parseSongs(result)
-               return list
-
-       def songGetSimilar(self, songId, limit):
-               result = self.callRemote("song.getSimilar", {"songID": songId, "limit": limit})
-               list = self.parseSongs(result)
-               return list
-
-       def artistGetSimilar(self, artistId, limit):
-               result = self.callRemote("artist.getSimilar", {"artistID": artistId, "limit": limit})
-               list = self.parseArtists(result)
-               return list
-
-       def songAbout(self, songId):
-               result = self.callRemote("song.about", {"songID": songId})
-               return result['result']['song']
-
-       def getVersion(self):
-               result = self.callRemote("service.getVersion", {})
-               return result
-
-       def parseSongs(self, items):
-               try:
-                       if 'result' in items:
-                               i = 0
-                               list = []
-                               if 'songs' in items['result']:
-                                       l = len(items['result']['songs'])
-                                       index = 'songs'
-                               elif 'song' in items['result']:
-                                       l = 1
-                                       index = 'song'
-                               else:
-                                       l = 0
-                                       index = ''
-                               while(i < l):
-                                       if index == 'songs':
-                                               s = items['result'][index][i]
-                                       else:
-                                               s = items['result'][index]
-                                       if 'estDurationSecs' in s:
-                                               dur = s['estDurationSecs']
-                                       else:
-                                               dur = 0
-                                       try:
-                                               notIn = True
-                                               for entry in list:
-                                                       songName = s['songName'].encode('ascii', 'ignore')
-                                                       albumName = s['albumName'].encode('ascii', 'ignore')
-                                                       artistName = s['artistName'].encode('ascii', 'ignore')
-                                                       if self.removeDuplicates == True:
-                                                               if (entry[0].lower() == songName.lower()) and (entry[3].lower() == albumName.lower()) and (entry[6].lower() == artistName.lower()):
-                                                                       notIn = False
-                                               if notIn == True:
-                                                       list.append([s['songName'].encode('ascii', 'ignore'),\
-                                                       s['songID'],\
-                                                       dur,\
-                                                       s['albumName'].encode('ascii', 'ignore'),\
-                                                       s['albumID'],\
-                                                       s['image']['tiny'].encode('ascii', 'ignore'),\
-                                                       s['artistName'].encode('ascii', 'ignore'),\
-                                                       s['artistID'],\
-                                                       s['image']['small'].encode('ascii', 'ignore'),\
-                                                       s['image']['medium'].encode('ascii', 'ignore')])
-                                       except:
-                                               print 'GrooveShark: Could not parse song number: ' + str(i)
-                                               traceback.print_exc()
-                                       i = i + 1
-                               return list
-                       else:
-                               return []
-                               pass
-               except:
-                       print 'GrooveShark: Could not parse songs. Got this:'
-                       traceback.print_exc()
-                       return []
-
-       def parseArtists(self, items):
-               try:
-                       if 'result' in items:
-                               i = 0
-                               list = []
-                               artists = items['result']['artists']
-                               while(i < len(artists)):
-                                       s = artists[i]
-                                       try:
-                                               list.append([s['artistName'].encode('ascii', 'ignore'),\
-                                               s['artistID']])
-                                       except:
-                                               print 'GrooveShark: Could not parse album number: ' + str(i)
-                                               traceback.print_exc()
-                                       i = i + 1
-                               return list
-                       else:
-                               return []
-               except:
-                       print 'GrooveShark: Could not parse artists. Got this:'
-                       traceback.print_exc()
-                       return []
-
-       def parseAlbums(self, items):
-               try:
-                       if 'result' in items:
-                               i = 0
-                               list = []
-                               albums = items['result']['albums']
-                               while(i < len(albums)):
-                                       s = albums[i]
-                                       try: # Avoid ascii ancoding errors
-                                               list.append([s['artistName'].encode('ascii', 'ignore'),\
-                                               s['artistID'],\
-                                               s['albumName'].encode('ascii', 'ignore'),\
-                                               s['albumID'],\
-                                               s['image']['medium'].encode('ascii', 'ignore')])
-                                       except:
-                                               print 'GrooveShark: Could not parse album number: ' + str(i)
-                                               traceback.print_exc()
-                                       i = i + 1
-                               return list
-                       else:
-                               return []
-               except:
-                       print 'GrooveShark: Could not parse albums. Got this'
-                       traceback.print_exc()
-                       return []
-
-       def parsePlaylists(self, items):
-               try:
-                       if 'result' in items:
-                               i = 0
-                               list = []
-                               playlists = items['result']['playlists']
-                               while(i < len(playlists)):
-                                       s = playlists[i]
-                                       try: # Avoid ascii ancoding errors
-                                               list.append([s['playlistID'],\
-                                               s['playlistName'].encode('ascii', 'ignore'),\
-                                               s['username'].encode('ascii', 'ignore')])
-                                       except:
-                                               print 'GrooveShark: Could not parse playlist number: ' + str(i)
-                                               traceback.print_exc()
-                                       i = i + 1
-                               return list
-                       else:
-                               return []
-               except:
-                       print 'GrooveShark: Could not parse playlists. Got this:'
-                       print items
-                       return []
index b14c3d5..edfab77 100644 (file)
@@ -1,4 +1,4 @@
-import socket, hmac, urllib, urllib2, pprint, md5, re, sha, time, random, os, pickle, uuid, tempfile
+import socket, hmac, urllib, urllib2, pprint, md5, re, sha, time, random, os, pickle, uuid, tempfile, pprint
 
 SESSION_EXPIRY = 518400 # 6 days in seconds
 
@@ -209,6 +209,202 @@ class GrooveSong:
                else:
                        return ''
 
+class GrooveAPIv1:
+       
+       def __init__(self, sessionID = 0):
+               import simplejson
+               self.simplejson = simplejson
+               timeout = 40
+               socket.setdefaulttimeout(timeout)
+               self.loggedIn = 0
+               self.userId = 0
+               self.sessionID = sessionID
+               
+       def callRemote(self, method, params={}):
+               data = {'header': {'sessionID': self.sessionID}, 'method': method, 'parameters': params}
+               data = self.simplejson.dumps(data)
+               req = urllib2.Request("http://api.grooveshark.com/ws/1.0/?json")
+               req.add_header('Host', 'api.grooveshark.com')
+               req.add_header('Content-type', 'text/json')
+               req.add_header('Content-length', str(len(data)))
+               req.add_data(data)
+               response = urllib2.urlopen(req)
+               result = response.read()
+               response.close()
+               try:
+                       result = self.simplejson.loads(result)
+                       if 'fault' in result:
+                               if result['fault']['code'] == 8: #Session ID has expired. Get a new and try again if possible.
+                                       print 'GrooveShark: SessionID expired'
+                                       return []
+                       return result
+               except:
+                       return []               
+               
+       def login(self, username, password):
+               if self.loggedIn == 1:
+                       return self.userId
+               token = md5.new(username.lower() + md5.new(password).hexdigest()).hexdigest()
+               result = self.callRemote("session.loginExt", {"username": username, "token": token})
+               if 'result' in result:
+                       if 'userID' in result['result']:
+                               self.loggedIn = 1
+                               self.userId = result['result']['userID']
+                               return result['result']['userID'] 
+               else:
+                       return 0
+               
+       def unfavorite(self, songID):
+               return self.callRemote("song.unfavorite", {"songID": songID})
+               
+       def playlistCreate(self, name, about):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.create", {"name": name, "about": about})
+                       if 'result' in result:
+                               return result['result']['playlistID']
+                       else:
+                               return 0
+               else:
+                       return 0
+
+       def playlistCreateUnique(self, name, songIds):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.createunique", {"name": name, "songIDs": songIds})
+                       if 'result' in result:
+                               return result['result']['playlistID']
+                       else:
+                               return 0
+               else:
+                       return 0
+                       
+       def playlistGetSongs(self, playlistId):
+               items = self.callRemote("playlist.getSongs", {"playlistID": playlistId})
+               print items
+               if 'result' in items:
+                       i = 0
+                       list = []
+                       index = ''
+                       l = -1
+                       try:
+                               if 'songs' in items['result'][0]:
+                                       l = len(items['result'][0]['songs'])
+                                       index = 'songs[]'
+                       except: pass
+                       try:
+                               if l < 0 and 'songs' in items['result']:
+                                       l = len(items['result']['songs'])
+                                       index = 'songs'
+                       except: pass
+                       try:
+                               if l < 0 and 'song' in items['result']:
+                                       l = 1
+                                       index = 'song'
+                       except: pass
+                       try:
+                               if l < 0:
+                                       l = len(items['result'])
+                       except: pass
+
+                       while(i < l):
+                               if index == 'songs[]':
+                                       s = items['result'][0]['songs'][i]
+                               elif index == 'songs':
+                                       s = items['result'][index][i]
+                               elif index == 'song':
+                                       s = items['result'][index]
+                               else:
+                                       s = items['result'][i]
+                               if 'CoverArtFilename' not in s:
+                                       info = self.getSongInfo(s['SongID'])
+                                       coverart = info['CoverArtFilename']
+                               elif s['CoverArtFilename'] != None:
+                                       coverart = THUMB_URL+s['CoverArtFilename'].encode('ascii', 'ignore')
+                               else:
+                                       coverart = 'None'
+                               list.append([s['SongName'].encode('ascii', 'ignore'),\
+                               s['SongID'],\
+                               s['AlbumName'].encode('ascii', 'ignore'),\
+                               s['AlbumID'],\
+                               s['ArtistName'].encode('ascii', 'ignore'),\
+                               s['ArtistID'],\
+                               coverart])
+                               i = i + 1
+                       return list
+               else:
+                       return []
+               
+               
+               return list
+                       
+       def playlistDelete(self, playlistId):
+               if self.loggedIn == 1:
+                       result =  self.callRemote("playlist.delete", {"playlistID": playlistId})
+                       if 'fault' in result:
+                               return 0
+                       else:
+                               return 1
+               else:
+                       return 0
+
+       def playlistRename(self, playlistId, name):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.rename", {"playlistID": playlistId, "name": name})
+                       if 'fault' in result:
+                               return 0
+                       else:
+                               return 1
+               else:
+                       return 0
+
+       def playlistClearSongs(self, playlistId):
+               if self.loggedIn == 1:
+                       return self.callRemote("playlist.clearSongs", {"playlistID": playlistId})
+
+       def playlistAddSong(self, playlistId, songId, position):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.addSong", {"playlistID": playlistId, "songID": songId, "position": position})
+                       if 'fault' in result:
+                               return 0
+                       else:
+                               return 1
+               else:
+                       return 0
+               
+       def playlistDeleteSong(self, playlistId, position):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.removeSong", {"playlistID": playlistId, "position": position})
+                       if 'fault' in result:
+                               return 0
+                       else:
+                               return 1
+               else:
+                       return 0
+                       
+       def playlistReplace(self, playlistId, songIds):
+               if self.loggedIn == 1:
+                       result = self.callRemote("playlist.replace", {"playlistID": playlistId, "songIDs": songIds})
+                       if 'fault' in result:
+                               return 0
+                       else:
+                               return 1
+               else:
+                       return 0
+               
+       def artistGetSimilar(self, artistId, limit):
+               items = self.callRemote("artist.getSimilar", {"artistID": artistId, "limit": limit})
+               if 'result' in items:
+                       i = 0
+                       list = []
+                       artists = items['result']['artists']
+                       while(i < len(artists)):
+                               s = artists[i]
+                               list.append([s['artistName'].encode('ascii', 'ignore'),\
+                               s['artistID']])
+                               i = i + 1
+                       return list
+               else:
+                       return []
+
 # Main API
 class GrooveAPI:
 
index 818c243..b1665ee 100644 (file)
@@ -1,8 +1,16 @@
 <settings>
+   <category label="User credentials">
    <setting id="username" type="text" label="30000" default=""/>
    <setting id="password" type="text" option="hidden" label="30001" default="" />
+   </category>
+   <category label="Limits">
    <setting id="songsearchlimit" type="labelenum" label="30002" default="20" values="5|10|15|20|25|30|40|50|60|70|80|90|100" />
    <setting id="albumsearchlimit" type="labelenum" label="30003" default="10" values="5|10|15|20|25|30|40|50|60|70|80|90|100" />
    <setting id="artistsearchlimit" type="labelenum" label="30004" default="10" values="5|10|15|20|25|30|40|50|60|70|80|90|100" />
    <setting id="songspagelimit" type="labelenum" label="30005" default="100" values="10|20|30|40|50|60|70|80|90|100|200|500" />
+   </category>
+   <category label="Advanced">
+   <setting type="lsep" label="Only set this is if you have a valid Grooveshark v1.0 API session id." />
+   <setting id="sessionidv1" type="text" label="30006" default=""/>
+   </category>
 </settings>
diff --git a/viewapi1sessionid.py b/viewapi1sessionid.py
new file mode 100644 (file)
index 0000000..88f67f7
--- /dev/null
@@ -0,0 +1,5 @@
+import pickle
+import os
+f = open('session.txt','rb')
+print pickle.load(f)
+