Libspotify声称播放列表容器在准备就绪之前已加载



我正在用C#制作一个.NET Spotify客户端,使用LibspotifyDotNet包装libspotify库,使用libspotify 12.1.51版本。

当我第一次加载会话播放列表容器时(即没有预先存在的设置位置),我会有一些奇怪的行为。该应用程序检查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_loadd回调的响应。

发挥作用的方法

// 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) libSpotify实际上不应该以这种方式使用——一次加载所有播放列表是一个非常糟糕的想法。我的账户上有几百个播放列表,其中有10000首曲目。如果我用我的账户登录你的应用程序,你试图像这样将所有播放列表加载到RAM中,你可能很快就会遇到RAM问题,尤其是在移动设备上。

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

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

4) libspotify是非常异步的。你之所以看到它们在第二次运行时立即加载,是因为libspotify缓存了一些东西,以便下次快速加载。要在第一次运行时正确接收播放列表,您需要等待,直到收到各种回调,告诉您内容已加载。

最新更新