I'm making a .NET Spotify client in C#, using LibspotifyDotNet to wrap around the libspotify library, using Libspotify version 12.1.51.
I'm getting some strange behaviour when loading the session playlistcontainer for the first time (i.e with no pre-existing settings location). The app checks libspotify's function to check that the playlistcontainer is loaded, which returns true, and then from this determines it's safe to go grab up all of the playlists. When it requests the number of playlists in the playlistcontainer, it gets 0 so doesn't load anything. A while after this, I get the callback saying the playlist is loaded, which does mean the app gets the playlists fine on subsequent runs, but not on the first one. Am I better off setting an additional 'isPlaylistReallyLoaded' flag upon this callback? Or is there something wrong here? I'll give my debugger output and then some of the relevant methods.
Debug output
libspotify> 09:27:28.211 I [user_cache:135] UserCache::initiateGetUsers() will query for 1 users
libspotify> 09:27:28.231 I [ap:1752] Connecting to AP ap.gslb.spotify.com:4070
The thread 'Win32 Thread' (0x172c) has exited with code 0 (0x0).
libspotify> 09:27:28.264 E [c:/Users/spotify-buildagent/BuildAgent/work/1e0ce8a77adfb2dc/client/core/network/proxy_resolver_win32.cpp:215] WinHttpGetProxyForUrl failed
libspotify> 09:27:28.337 I [offline-mgr:2084] Storage has been cleaned
The thread 'Win32 Thread' (0x16f8) has exited with code 0 (0x0).
Itterating over loaded playlists
libspotify> 09:27:44.155 E [ap:1694] AP Socket Error: Undefined Error 0x4E20 (20000)
libspotify> 09:27:45.381 E [ap:3915] Connection error: 117
libspotify> 09:27:54.065 I [ap:1752] Connecting to AP ap.gslb.spotify.com:4070
0 playlists found
libspotify> 09:27:56.290 I [ap:1226] Connected to AP: 78.31.12.21:4070
libspotify> 09:28:03.035 I [user_cache:135] UserCache::initiateGetUsers() will query for 1 users
libspotify> 09:28:03.177 I [user_cache:135] UserCache::initiateGetUsers() will query for 100 users
libspotify> 09:28:03.271 W [core/playlist/playlist.h:45] Adding observer while updating
libspotify> 09:28:03.297 W [core/playlist/playlist.h:45] Adding observer while updating
libspotify> 09:28:03.325 W [core/playlist/playlist.h:45] Adding observer while updating
libspotify> 09:28:03.353 W [core/playlist/playlist.h:45] Adding observer while updating
playlist_added at position 0
playlist_added at position 1
playlist_added at position 2
playlist_added at position 3
playlist_added at position 4
playlist_added at position 5
playlist_added at position 6
playlist_added at position 7
playlist_added at position 8
container_loaded
libspotify> 09:28:03.644 W [core/playlist/playlist.h:45] Adding observer while updating
Where the line that says "Iterating over playlists" is where I've checked the loaded state of the playlist and found true and am going to enter the GetAllPlaylists() method. The line that says 0 playlists found is output after that loop has run, showing how many playlists were returned when checking sp_playlistcontainer_num_playlists. The line stating 'container_loaded' is in response to the container_loaded callback on the playlistcontainer.
Methods at play
// this is the method that is called upon login to get the user's playlists
public static List<PlaylistContainer.PlaylistInfo> GetAllSessionPlaylists()
{
waitFor(delegate
{
return PlaylistContainer.GetSessionContainer().IsLoaded
&& PlaylistContainer.GetSessionContainer().PlaylistsAreLoaded;
}, REQUEST_TIMEOUT);
return PlaylistContainer.GetSessionContainer().GetAllPlaylists();
}
Within the PlaylistContainer model class
public static PlaylistContainer GetSessionContainer()
{
if (_sessionContainer == null) {
if (Session.GetSessionPtr() == IntPtr.Zero)
throw new InvalidOperationException("No valid session.");
_sessionContainer = new PlaylistContainer(libspotify.sp_session_playlistcontainer(Session.GetSessionPtr()));
}
return _sessionContainer;
}
public bool IsLoaded {
get {
return libspotify.sp_playlistcontainer_is_loaded(_containerPtr);
}
}
public bool PlaylistsAreLoaded {
get {
if (!this.IsLoaded)
return false;
int count = libspotify.sp_playlistcontainer_num_playlists(_containerPtr);
for (int i = 0; i < count; i++) {
if(libspotify.sp_playlistcontainer_playlist_type(_containerPtr, i) == libspotify.sp_playlist_type.SP_PLAYLIST_TYPE_PLAYLIST) {
using (Playlist p = Playlist.Get(libspotify.sp_playlistcontainer_playlist(_containerPtr, i))) {
if (!p.IsLoaded)
return false;
}
}
}
return true;
}
}
public List<PlaylistInfo> GetAllPlaylists() {
if (!GetSessionContainer().IsLoaded)
throw new InvalidOperationException("Container is not loaded.");
List<PlaylistInfo> playlists = new List<PlaylistInfo>();
Logger.WriteDebug("Itterating over loaded playlists");
int count = libspotify.sp_playlistcontainer_num_playlists(_containerPtr);
for (int i = 0; i < count; i++) {
if (libspotify.sp_playlistcontainer_playlist_type(_containerPtr, i) == libspotify.sp_playlist_type.SP_PLAYLIST_TYPE_PLAYLIST) {
IntPtr playlistPtr = libspotify.sp_playlistcontainer_playlist(_containerPtr, i);
playlists.Add(new PlaylistInfo() {
Pointer = playlistPtr,
PlaylistType = libspotify.sp_playlist_type.SP_PLAYLIST_TYPE_PLAYLIST,
ContainerPtr = _containerPtr,
Name = Functions.PtrToString(libspotify.sp_playlist_name(playlistPtr))
});
}
}
Logger.WriteDebug("{0} playlists found", count);
return playlists;
}
I've borrowed a lot of my API interaction code from the Jamcast plugin (the only example out there really) and fixed problems as I've found them. But coming at this as a novice in Spotify's API, it seemed like a good way to start. I'm gradually rewriting it little by little. So as an additional question, is it worth me completely rewriting out the Jamcast stuff and starting over before I get it out there?
I know there's a lot there already, but if you need more info, let me know. I appreciate any help that you can give this libspotify noob.