Get artist's most popular songs.
authorstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Tue, 25 Jan 2011 16:30:24 +0000 (16:30 +0000)
committerstephendenham <stephendenham@2dec19e3-eb1d-4749-8193-008c8bba0994>
Tue, 25 Jan 2011 16:30:24 +0000 (16:30 +0000)
Allow multiple pages in songs directory.

git-svn-id: svn://svn.code.sf.net/p/xbmc-groove/code@39 2dec19e3-eb1d-4749-8193-008c8bba0994

changelog.txt
default.py
resources/img/popularSongsArtist.png [new file with mode: 0644]
resources/language/English/strings.xml
resources/lib/GroovesharkAPI.py
resources/settings.xml

index bd0b23e..c7d5e5b 100644 (file)
@@ -1,9 +1,12 @@
 0.3.0:
 
-Add search of artist's albums.
+Get artist's albums.
+Get artist's most popular songs.
+Get other user's playlists.
+
 Sort playlists directory by name.
-Track name first in album and playlist directory item labels.
-Get other users' playlists.
+Put track name first in the album and playlist directory item labels.
+Allow multiple pages in the songs directory (help prevent slow retrieval of very big lists).
 
 0.2.3:
 
index 7fdcb3d..f515407 100644 (file)
@@ -1,17 +1,19 @@
-import urllib, sys, os, shutil, re, time, xbmcaddon, xbmcplugin, xbmcgui, xbmc
+import urllib, sys, os, shutil, re, time, xbmcaddon, xbmcplugin, xbmcgui, xbmc, pickle
 MODE_SEARCH_SONGS = 1
 MODE_SEARCH_ALBUMS = 2
 MODE_SEARCH_ARTISTS = 3
 MODE_SEARCH_ARTISTS_ALBUMS = 4
 MODE_SEARCH_PLAYLISTS = 5
-MODE_POPULAR_SONGS = 6
-MODE_FAVORITES = 7
-MODE_PLAYLISTS = 8
-MODE_ALBUM = 9
-MODE_ARTIST = 10
-MODE_PLAYLIST = 11
-MODE_SONG = 12
-MODE_FAVORITE = 13
+MODE_ARTIST_POPULAR = 6
+MODE_POPULAR_SONGS = 7
+MODE_FAVORITES = 8
+MODE_PLAYLISTS = 9
+MODE_ALBUM = 10
+MODE_ARTIST = 11
+MODE_PLAYLIST = 12
+MODE_SONG_PAGE = 13
+MODE_SONG = 14
+MODE_FAVORITE = 15
 
 ACTION_MOVE_LEFT = 1
 ACTION_MOVE_UP = 3
@@ -67,6 +69,7 @@ class Groveshark:
     playlistImg = xbmc.translatePath(os.path.join(imgDir, 'playlist.png'))
     usersplaylistsImg = xbmc.translatePath(os.path.join(imgDir, 'usersplaylists.png'))
     popularSongsImg = xbmc.translatePath(os.path.join(imgDir, 'popularSongs.png'))
+    popularSongsArtistImg = xbmc.translatePath(os.path.join(imgDir, 'popularSongsArtist.png'))
     songImg = xbmc.translatePath(os.path.join(imgDir, 'song.png'))
     defImg = xbmc.translatePath(os.path.join(imgDir, 'default.tbn'))
     fanImg = xbmc.translatePath(os.path.join(baseDir, 'fanart.png'))
@@ -75,6 +78,7 @@ class Groveshark:
     songsearchlimit = int(settings.getSetting('songsearchlimit'))
     albumsearchlimit = int(settings.getSetting('albumsearchlimit'))
     artistsearchlimit = int(settings.getSetting('artistsearchlimit'))
+    songspagelimit = int(settings.getSetting('songspagelimit'))
     username = settings.getSetting('username')
     password = settings.getSetting('password')
     userid = 0
@@ -102,6 +106,7 @@ class Groveshark:
         self._add_dir('Search for artists...', '', MODE_SEARCH_ARTISTS, self.artistImg, 0)
         self._add_dir("Search for artist's albums...", '', MODE_SEARCH_ARTISTS_ALBUMS, self.artistsAlbumsImg, 0)
         self._add_dir("Search for user's playlists...", '', MODE_SEARCH_PLAYLISTS, self.usersplaylistsImg, 0)
+        self._add_dir('Popular songs for artist...', '', MODE_ARTIST_POPULAR, self.popularSongsArtistImg, 0)
         self._add_dir('Popular songs', '', MODE_POPULAR_SONGS, self.popularSongsImg, 0)
         if (self.userid != 0):
             self._add_dir('My favorites', '', MODE_FAVORITES, self.favoritesImg, 0)
@@ -151,7 +156,7 @@ class Groveshark:
 
     # Search for playlists
     def searchPlaylists(self):
-        query = self._get_keyboard(default="", heading="Search for user's playlists")
+        query = self._get_keyboard(default="", heading="Username")
         if (query != ''): 
             playlists = groovesharkApi.getUserPlaylistsEx(query)
             if (len(playlists) > 0):
@@ -254,6 +259,29 @@ class Groveshark:
             dialog = xbmcgui.Dialog()
             dialog.ok('Grooveshark XBMC', 'You must be logged in', 'to get Grooveshark playlists.')
             
+    # Show popular songs of the artist
+    def artistPopularSongs(self):
+        query = self._get_keyboard(default="", heading="Artist")
+        if (query != ''): 
+            artists = groovesharkApi.getArtistSearchResults(query, limit = self.artistsearchlimit)
+            if (len(artists) > 0):
+                artist = artists[0]
+                artistID = artist[1]
+                xbmc.log("Found " + artist[0] + "...")
+                songs = groovesharkApi.getArtistPopularSongs(artistID, limit = self.songsearchlimit)
+                if (len(songs) > 0):
+                    self._add_songs_directory(songs, trackLabelFormat=NAME_ALBUM_ARTIST_LABEL)
+                else:
+                    dialog = xbmcgui.Dialog()
+                    dialog.ok('Grooveshark XBMC', 'No popular songs.')
+                    self.categories()
+            else:
+                dialog = xbmcgui.Dialog()
+                dialog.ok('Grooveshark XBMC', 'No matching artists.')
+                self.categories()
+        else:
+            self.categories()
+            
     # Play a song
     def playSong(self, item):
         songid = item.getProperty('songid')
@@ -284,6 +312,10 @@ class Groveshark:
         
         return item
     
+    # Next page of songs
+    def songPage(self, page, trackLabelFormat):
+        self._add_songs_directory([], trackLabelFormat, page)
+        
     # Get keyboard input
     def _get_keyboard(self, default="", heading="", hidden=False):
         kb = xbmc.Keyboard(default, heading, hidden)
@@ -332,12 +364,29 @@ class Groveshark:
             return thumbDef
     
     # Add songs to directory
-    def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL):
-        n = len(songs)
-        xbmc.log("Found " + str(n) + " songs...")
-        i = 0
-        while i < n:
-            song = songs[i]
+    def _add_songs_directory(self, songs, trackLabelFormat=ARTIST_ALBUM_NAME_LABEL, page=0):
+
+        totalSongs = len(songs)
+        page = int(page)
+
+        # No pages needed
+        if page == 0 and totalSongs <= self.songspagelimit:
+            xbmc.log("Found " + str(totalSongs) + " songs...")
+        # Pages
+        else:
+            # Cache all songs
+            if page == 0:
+                self._setSavedSongs(songs)
+            else:
+                songs = self._getSavedSongs()
+                totalSongs = len(songs)
+                
+            if totalSongs > 0:
+                start = page * self.songspagelimit
+                end = start + self.songspagelimit
+                songs = songs[start:end]
+        
+        for song in songs:
             item = self._get_song_item(song, trackLabelFormat)
             coverart = item.getProperty('coverart')
             songname = song[0]
@@ -352,8 +401,12 @@ class Groveshark:
             menuItems = []
             menuItems.append(("Grooveshark favorite", "XBMC.RunPlugin("+fav+")"))
             item.addContextMenuItems(menuItems, replaceItems=False)
-            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False, totalItems=n)
-            i = i + 1
+            xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=item,isFolder=False, totalItems=len(songs))
+
+        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)
+            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)
@@ -407,11 +460,38 @@ class Groveshark:
       
     # Add whatever directory
     def _add_dir(self, name, url, mode, iconimage, id, items=1):
-        
-        u=sys.argv[0]+"?mode="+str(mode)+"&name="+urllib.quote_plus(name)+"&id="+str(id)
+        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 } )
         return xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]),url=u,listitem=dir,isFolder=True, totalItems=items)
+    
+    def _getSavedSongs(self):
+        path = os.path.join(cacheDir, 'songs.dmp')
+        try:
+            f = open(path, 'rb')
+            songs = pickle.load(f)
+            f.close()
+        except:
+            songs = []
+            pass
+        return songs
+
+    def _setSavedSongs(self, songs):            
+        try:
+            # Create the 'data' directory if it doesn't exist.
+            if not os.path.exists(cacheDir):
+                os.makedirs(cacheDir)
+            path = os.path.join(cacheDir, 'songs.dmp')
+            f = open(path, 'wb')
+            pickle.dump(songs, f, protocol=pickle.HIGHEST_PROTOCOL)
+            f.close()
+        except:
+            xbmc.log("An error occurred saving songs")
+            pass
+    
 
 
 # Parse URL parameters
@@ -465,12 +545,22 @@ elif mode==MODE_SEARCH_PLAYLISTS:
 
 elif mode==MODE_POPULAR_SONGS:
     grooveshark.popularSongs()
+    
+elif mode==MODE_ARTIST_POPULAR:
+    grooveshark.artistPopularSongs()
 
 elif mode==MODE_FAVORITES:
     grooveshark.favorites()
 
 elif mode==MODE_PLAYLISTS:
     grooveshark.playlists()
+    
+elif mode==MODE_SONG_PAGE:
+    try: page=urllib.unquote_plus(params["page"])
+    except: pass
+    try: label=urllib.unquote_plus(params["label"])
+    except: pass
+    grooveshark.songPage(page, label)
 
 elif mode==MODE_SONG:
     try: name=urllib.unquote_plus(params["name"])
@@ -495,6 +585,6 @@ elif mode==MODE_PLAYLIST:
     
 elif mode==MODE_FAVORITE:
     grooveshark.favorite(id)
-
+    
 if mode < MODE_SONG:
     xbmcplugin.endOfDirectory(int(sys.argv[1]))
diff --git a/resources/img/popularSongsArtist.png b/resources/img/popularSongsArtist.png
new file mode 100644 (file)
index 0000000..00c6d0b
Binary files /dev/null and b/resources/img/popularSongsArtist.png differ
index 6fea7bc..ca757da 100644 (file)
@@ -5,4 +5,5 @@
        <string id="30002">Song search limit</string>
        <string id="30003">Album search limit</string>
        <string id="30004">Artist search limit</string>
+       <string id="30005">Number of songs per page</string>
 </strings>
\ No newline at end of file
index d571670..85dc5a1 100644 (file)
@@ -377,7 +377,15 @@ class GrooveAPI:
                        return self._parseSongs(result)
                else:
                        return []
-               
+
+       # Get artist's popular songs
+       def getArtistPopularSongs(self, artistID, limit = SONG_LIMIT):
+               result = self._callRemote('getArtistPopularSongs', {'artistID' : artistID})
+               if 'result' in result:
+                       return self._parseSongs(result, limit)
+               else:
+                       return []
+
        # Gets the popular songs
        def getPopularSongsToday(self, limit=SONG_LIMIT):
                result = self._callRemote('getPopularSongsToday', {'limit' : limit})
@@ -490,19 +498,34 @@ class GrooveAPI:
                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 = len(items['result'])
-                               index = ''
+                       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
+
                        if limit > 0 and l > limit:
                                l = limit
                        while(i < l):
-                               if index == 'songs':
+                               if index == 'songs[]':
+                                       s = items['result'][0]['songs'][i]
+                               elif index == 'songs':
                                        s = items['result'][index][i]
                                elif index == 'song':
                                        s = items['result'][index]
@@ -610,5 +633,6 @@ class GrooveAPI:
 #res = groovesharkApi.addUserFavoriteSong('27425375')
 #res = groovesharkApi.logout()
 #res = groovesharkApi.getUserPlaylistsEx('stephendenham')
+#res = groovesharkApi.getArtistPopularSongs('3707')
 #
 #pprint.pprint(res)
index 69a0dc8..818c243 100644 (file)
@@ -4,4 +4,5 @@
    <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" />
 </settings>