0

我正在用 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_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 的任何帮助。

4

1 回答 1

0

几点注意事项:

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

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

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

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

于 2013-07-22T11:58:19.463 回答