声明播放列表容器的Libspotify在准备好之前已加载

时间:2013-07-20 10:46:20

标签: spotify libspotify

我正在使用Libspotify版本12.1.51在C#中创建.NET Spotify客户端,使用LibspotifyDotNet包装libspotify库。

第一次加载会话播放列表容器时,我遇到了一些奇怪的行为(即没有预先存在的设置位置)。该应用程序检查libspotify的函数以检查播放列表容器是否已加载,返回true,然后从此确定可以安全地获取所有播放列表。当它请求播放列表容器中的播放列表数量时,它变为0,因此不加载任何内容。在此之后的一段时间,我得到回调说播放列表已加载,这意味着应用程序在后续运行中获取播放列表,但不是第一个播放列表。我最好在这次回调时设置一个额外的'isPlaylistReallyLoaded'标志吗?或者这里有什么问题吗?我将给出我的调试器输出,然后给出一些相关的方法。

调试输出

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

如果显示“迭代播放列表”的行是我已检查播放列表的加载状态并发现为true并将进入GetAllPlaylists()方法的位置。找到0个播放列表的行在该循环运行后输出,显示在检查sp_playlistcontainer_num_playlists时返回了多少个播放列表。说明'container_loaded'的行是为了响应播放列表容器上的container_loaded回调。

正在发挥作用的方法

// 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();
}

在PlaylistContainer模型类

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;
}

我从Jamcast插件中借用了很多我的API交互代码(这是真正的唯一例子)并修复了我发现它们的问题。但作为Spotify API的新手,这似乎是一个很好的开始。我逐渐重写它。所以作为一个额外的问题,是否值得我完全重写Jamcast的东西并在我把它拿出来之前重新开始?

我知道那里已经有很多,但如果你需要更多信息,请告诉我。我感谢您为libspotify noob提供的任何帮助。

1 个答案:

答案 0 :(得分:0)

一些注意事项:

1)libSpotify并不是真的应该以这种方式使用 - 一次加载所有播放列表是一个非常糟糕的主意。我的帐户上有几百个播放列表,其中包含10,000个曲目。如果我使用我的帐户登录您的应用程序并尝试将所有播放列表加载到这样的RAM中,您很可能会很快遇到RAM问题,尤其是在移动设备上。

2)播放列表容器和播放列表本身在加载方面完全分开。加载容器时,所有这意味着它知道列表中所有播放列表的文件夹名称和播放列表URI。没什么。

3)如您的日志所示,播放列表容器未完全加载,直到container_loaded回调被触发。我认为当容器处于加载过程中时sp_playlistcontainer_is_loaded仅返回false。因此,只要您登录它就会从缓存中读取列表并将_is_loaded设置为true。然后,它将开始从缓存列表中接收对增量列表的更新(正如您在日志中看到的那样,接收这些playlist_added回调。最后,它将触发container_loaded回调。

4)libspotify 非常异步。您在第二次运行时直接加载它们的原因是因为libspotify会缓存下次快速加载的内容。要在第一次运行时正确接收播放列表,您需要等到各种回调告诉您已填充内容。