一些调研与思考 ============== .. _research-model: 怎样较好的抽象不同的资源提供方? -------------------------------- feeluown 的一个主要目标就是将各个资源进行抽象,统一上层使用资源的方式。 但各个资源提供方提供的 API 差异较大,功能差别不小,比如网易云音乐 会提供批量接口(根据歌曲 id 批量获取歌曲详情),而虾米和 QQ 音乐就没有 类似接口,这给 feeluown 的实现和设计带来了挑战。 问题一:同一平台,不同接口的返回信息有的比较完整,有的不完整 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 我们以网易云音乐的 `专辑详细信息接口` 和 `搜索接口` 为例。 它的搜索接口返回的专辑信息大致如下:: "album": { "artist": { "id": 0, "alias": [], "img1v1": 0, "name": "", "picUrl": null, "picId": 0, }, "id": 2960228, "name": "\u5218\u5fb7\u534e Unforgettable Concert 2010", "picId": 2540971374328644, ... } 它没有专辑封面的链接,也没有专辑歌曲、歌手信息也不完整信息。 而专辑详细信息接口中,它就有 `songs` , `artists` , `picUrl` 等信息。 面对这个问题,目前有两种解决方案: 1. 将搜索接口返回的 Album 定义为 BriefAlbumModel,将详细接口返回的定义为 AlbumModel - pros: 清晰明了,两者有明显的区分 - cons: 多一个 Model 就多一个概念,上层要对两者进行区分,代码更复杂 2. 定义一个 AlbumModel,创建 Model 实例的时候不要求所有字段都有值, 一些字段的值在之后在被真正用到的时候再自动获取。 - cons: 比较隐晦 - cons: 上层不也方便确认哪些字段是已经有值了,哪些会在调用的时候获取 .. note:: **UPDATE 2019-05-04**: 第二种方案使用已经半年了,我们发现它有一个让人头疼的问题: 类似 ``model.xxx`` 这样的代码可能会导致整个线程 block,而对于一个 GUI 程序来说, block(主)线程是不可接受的。为了不阻塞,我们使用的方案是让 ``model.xxx`` 这个操作跑在另一个线程中,这样的代码目前在 ``songs_table_container.py`` 中有较多使用。但这样的代码看起来很丑,性能也比较差(见 ``research/bench_getattr.py`` )。 另外,尽管我们在开发 feeluown 的时候可以额外的注意,让程序不因此卡住, 但是其它插件开发者并不一定完全了解这个机制,很容易写成“坏”的代码。 为了让整体代码更简单,目前使用的是第二种方案。上层假设 identifier/name 等字段是一开始就有了,url/artists 等字段需要之后调用接口才会有值。 (尽管这种方案看起来也有明显的缺点,但目前看来可以接受,也没想到更好的方法。欢迎大家讨论新的方案)。 问题二:不同平台,同一接口的返回信息有的比较完整,有的不完整 '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' 在虾米音乐中,在获取歌曲详细信息的时候,就可以获取这歌曲的播放链接。 但是在网易云音乐,需要单独调用一个接口来获取歌曲的播放链接。 在虾米音乐的 API 中,要获取一个歌手的所有信息,我们需要调用它的多个接口: 一个是歌手详情接口;另一个是歌手歌曲详情接口;还有歌手专辑接口等。 问题三:平台能力方面和开发体验 '''''''''''''''''''''''''''''' 另一方面,就算各音乐平台都提供一样的 API,开发者在开发相关插件的时候, 也不一定会一次性把所有功能都完成,那时,也会存在一个问题: A 插件有某功能,但是 B 插件没有。 所以,当 B 插件没有该功能的时候,系统内部应该怎样处理?又怎样将该 问题呈现给用户呢? 举个例子,对于网易云音乐来说,它的批量获取歌曲功能可以这样实现:: NeteaseSongModel.list(song_ids): -> list 但是我们不能给虾米音乐和 QQ 音乐实现这样的功能,那怎么办, 目前有如下方法:: 1. XiamiSongModel.list(song_ids): -> raise NotSupportedError 2. XiamiSongModel.list -> AttributeError # 好像不太优雅 3. XiamiSongModel.allow_batch -> 加一个标记字段 目前使用的是第三种方案,加一个标记字段, ``allow_get`` 和 ``allow_batch`` 。