From eab0702919b86eb092e3ee37cafa52d85fa5d177 Mon Sep 17 00:00:00 2001 From: Shaowen Yin Date: Tue, 26 Nov 2024 00:34:34 +0800 Subject: [PATCH] [*](docs/gui): fix provider-switch add some comments and docs (#886) --- docs/source/index.rst | 3 +- docs/source/media_assets_management/index.rst | 41 ++++++ .../media_assets_management/index_v2.rst | 10 -- .../media_assets_management/library.rst | 23 ++++ docs/source/media_assets_management/model.rst | 8 ++ .../media_assets_management/provider.rst | 31 +++++ .../source/media_assets_management/topics.rst | 5 - docs/source/media_assets_management_v1.rst | 121 ------------------ feeluown/gui/components/avatar.py | 8 +- feeluown/gui/provider_ui.py | 14 +- 10 files changed, 122 insertions(+), 142 deletions(-) create mode 100644 docs/source/media_assets_management/index.rst delete mode 100644 docs/source/media_assets_management/index_v2.rst create mode 100644 docs/source/media_assets_management/library.rst create mode 100644 docs/source/media_assets_management/model.rst create mode 100644 docs/source/media_assets_management/provider.rst delete mode 100644 docs/source/media_assets_management/topics.rst delete mode 100644 docs/source/media_assets_management_v1.rst diff --git a/docs/source/index.rst b/docs/source/index.rst index 9f407d2b7a..543ef9f311 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -30,8 +30,7 @@ FeelUOwn 是一个用户友好、可玩性强的播放器 dev_quickstart arch api - media_assets_management_v1 - media_assets_management/index_v2 + media_assets_management/index protocol glossary research diff --git a/docs/source/media_assets_management/index.rst b/docs/source/media_assets_management/index.rst new file mode 100644 index 0000000000..7800d81953 --- /dev/null +++ b/docs/source/media_assets_management/index.rst @@ -0,0 +1,41 @@ +媒体资源管理 +=================== + +feeluown 一个设计目标是让用户能够高效使用各个音乐平台的合法资源。 +媒体资源管理定义、规范并统一了各个音乐平台资源的访问接口。 + +音乐库是媒体资源管理子系统的入口。音乐库部分负责管理 feeluown 的音乐资源, +包括歌曲、歌手、专辑详情获取,专辑、歌单封面获取等。它主要由几个部分组成: +音乐对象模型(*Model*)、音乐提供方(*Provider*)、提供方管理(*Library*)。 + +.. code:: + + +---------------------------------------------------------------------------+ + | +---------+ | + | | Library | | + | +---------+ +-------------+ | + | | | song_get | | + | | +-------------------+ | ... | | + | |--| provider(netease) |--| aritst_get |-----+ | + | | +-------------------+ | search | | +----------------+ | + | | | ... | | | BriefSongModel | | + | | +-------------+ | | ... | | + | | +-------------+ +-----| | | + | | | song_get_mv | | | SongModel | | + | | +-----------------+ | ... | | | ArtistModel | | + | |--| provider(xiami) |--| album_get |-------+ | ... | | + | | +-----------------+ | search | +----------------+ | + | | | ... | | + | | +-------------+ | + | |--... | + | | + +---------------------------------------------------------------------------+ + + +.. toctree:: + :maxdepth: 2 + :caption: 目录 + + library + provider + model diff --git a/docs/source/media_assets_management/index_v2.rst b/docs/source/media_assets_management/index_v2.rst deleted file mode 100644 index 7ff78897b3..0000000000 --- a/docs/source/media_assets_management/index_v2.rst +++ /dev/null @@ -1,10 +0,0 @@ -媒体资源管理 v2 -=================== - -媒体资源管理对应的代码模块主要是 `feeluown.library` 包。 - -.. toctree:: - :maxdepth: 2 - :caption: 目录 - - topics diff --git a/docs/source/media_assets_management/library.rst b/docs/source/media_assets_management/library.rst new file mode 100644 index 0000000000..25f65f13db --- /dev/null +++ b/docs/source/media_assets_management/library.rst @@ -0,0 +1,23 @@ +音乐库 +===================== + +.. _library: + +音乐库模块管理资源提供方(*Provider*)。音乐库还提供了一些通用接口,简化了对资源提供方的访问。 + +.. code:: + + # 注册一个资源提供方 + library.register(provider) + + # 获取资源提供方实例 + provider = library.get(provider.identifier) + + # 列出所有资源提供方 + library.list() + + # 在音乐库中搜索关键词 + library.search('linkin park') + +.. autoclass:: feeluown.library.Library + :members: diff --git a/docs/source/media_assets_management/model.rst b/docs/source/media_assets_management/model.rst new file mode 100644 index 0000000000..9fd15b131b --- /dev/null +++ b/docs/source/media_assets_management/model.rst @@ -0,0 +1,8 @@ +数据模型 +===================== + +feeluown 定义了常见音乐资源的数据模型,包括歌曲、歌手、专辑、视频、MV、歌单等。 +这样,上层模块就能以统一的方式访问这些资源。 + +.. automodule:: feeluown.library.models + :members: diff --git a/docs/source/media_assets_management/provider.rst b/docs/source/media_assets_management/provider.rst new file mode 100644 index 0000000000..81ba4bf30f --- /dev/null +++ b/docs/source/media_assets_management/provider.rst @@ -0,0 +1,31 @@ +资源提供方 +===================== + +歌曲等音乐资源都来自于某一个提供方。比如,我们认为本地音乐的提供方是本地, +网易云音乐资源的提供方是网易,等等。对应到程序设计上,每个提供方都对应一个 provider 实例。 +provider 是我们访问具体一个音乐平台资源音乐的入口。 + +在 feeluown 生态中,每个音乐资源提供方都对应着一个插件,我们现在有 feeluown-local/feeluown-netease +等许多插件,这些插件在启动时,会注册一个 provider 实例到 feeluown 的音乐库模块上。 +注册完成之后,音乐库和 feeluown 其它模块就能访问到这个提供方的资源 + +举个栗子,feeluown-local 插件在启动时就创建了一个 *identifier* 为 ``local`` 的 provider 实例, +并将它注册到音乐库中,这样,当我们访问音乐库资源时,就能访问到本地音乐资源。 + +详细信息请参考 :doc:`provider`。 + +定义一个资源提供方 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. autoclass:: feeluown.library.AbstractProvider + :members: + +.. autoclass:: feeluown.library.Provider + :members: + +协议 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: feeluown.library.provider_protocol + :members: + diff --git a/docs/source/media_assets_management/topics.rst b/docs/source/media_assets_management/topics.rst deleted file mode 100644 index ac4136924e..0000000000 --- a/docs/source/media_assets_management/topics.rst +++ /dev/null @@ -1,5 +0,0 @@ -经典话题 -======================== - -音乐多音质 -~~~~~~~~~~~~~~~~ diff --git a/docs/source/media_assets_management_v1.rst b/docs/source/media_assets_management_v1.rst deleted file mode 100644 index e4d82ee41e..0000000000 --- a/docs/source/media_assets_management_v1.rst +++ /dev/null @@ -1,121 +0,0 @@ -(Deprecated) 媒体资源管理 v1 -================================= - -feeluown 一个设计目标是让用户能够合理整合并高效使用自己在各个音乐平台能获取的资源。 -而每个平台提供资源数据的方式都有差异。有的可能已经公开的 RESTful API,它可以获取到资源的元信息, -并且也有接口可以获取到资源的链接;而有的平台则没有公开的可用接口,但是通过一些技术手段(如爬虫), -也可以获取到平台的资源。另外,每个平台的资源模型也有差异。有的平台会用一个非常大的结构体来表示一首歌曲; -而有的平台会有很多个小结构体,来拼凑出一首歌曲的全部信息。这些平台的差异给 feeluown 的架构设计带来了一些挑战, -feeluown 通过“媒体资源管理”子系统来解决这些困难。 - -音乐库是媒体资源管理子系统的入口。音乐库部分负责管理 feeluown 的音乐资源,包括歌曲、歌手、专辑详情获取, -专辑、歌单封面获取及缓存(这是设计目标,部分逻辑目前未实现)。它主要由几个部分组成: -音乐对象模型(*Model*)、音乐提供方(*Provider*)、提供方管理(*Library*)。 - -.. code:: - - +-------------------------------------------------------------------------+ - | +---------+ | - | | Library | | - | +---------+ +--------+ | - | | | Models | | - | | +-------------------+ | Song | | - | |--| provider(netease) | -| Artist |---- | - | | +-------------------+ | Album | | +--------------+ | - | | | ... | | | Model Spec | | - | | +--------+ | duck typing | (Base Model) | | - | | |-------------| | | - | | +--------+ | | BaseSong | | - | | +-----------------+ | Models | | | BaseArtist | | - | |--| provider(xiami) |-| Song |------- | ... | | - | | +-----------------+ | ... | +--------------+ | - | | +--------+ | - | | | - | |--... | - | | - +-------------------------------------------------------------------------+ - - -.. _library: - -音乐库 -~~~~~~~~~~~~~~ - -音乐库模块管理资源提供方(*Provider*)。 - -.. code:: - - # 注册一个资源提供方 - library.register(provider) - - # 获取资源提供方实例 - provider = library.get(provider.identifier) - - # 列出所有资源提供方 - library.list() - - # 在音乐库中搜索关键词 - library.search('linkin park') - - -.. autoclass:: feeluown.library.Library - :members: - - -资源提供方 -~~~~~~~~~~~~~~~~~~~~ -歌曲等音乐资源都来自于某一个提供方。比如,我们认为本地音乐的提供方是本地, -网易云音乐资源的提供方是网易,等等。对应到程序设计上,每个提供方都对应一个 provider 实例。 -provider 是我们访问具体一个音乐平台资源音乐的入口。 - -在 feeluown 生态中,每个音乐资源提供方都对应着一个插件,我们现在有 feeluown-local/feeluown-netease -等许多插件,这些插件在启动时,会注册一个 provider 实例到 feeluown 的音乐库模块上。 -注册完成之后,音乐库和 feeluown 其它模块就能访问到这个提供方的资源 - -举个栗子,feeluown-local 插件在启动时就创建了一个 *identifier* 为 ``local`` 的 provider 实例, -并将它注册到音乐库中,这样,当我们访问音乐库资源时,就能访问到本地音乐资源。 - -这个过程抽象为代码的话,它就类似: - -.. code:: python - - result = library.serach() - # we will see nothing in result because library has no provider - - from fuo_local import provider - library.register(provider) - - result = library.search('keyword') - # we may see that some local songs are in the search result - -每个 provider 实例,它都需要提供访问具体资源的入口。举个栗子, - -.. code:: python - - from fuo_local import provider - - # we can get a song instance by a song identifier - song = provider.Song.get(song_id) - - # we can also get a artist instance by a artist identifier - artist = provider.Artist.get(artist_id) - - -下面是音乐资源提供方的抽象基类,我们推荐大家基于此来实现一个 Provider 类。 - -.. autoclass:: feeluown.library.AbstractProvider - :members: - - -当我们访问一个音乐提供方的资源时,不同的用户对不同资源的权限也是不一样的。 -如果我们需要以特定的身份来访问音乐资源,我们可以使用 provider 的 ``auth`` 和 ``auth_as`` 方法: - -.. code:: python - - from fuo_netease import provider - user_a = obj # UserModel - provider.auth(user_a) - - # 使用 auth_as 来临时切换用户身份 - with provider.auth_as(user_b): - provider.Song.get(song_id) diff --git a/feeluown/gui/components/avatar.py b/feeluown/gui/components/avatar.py index ee2779748d..da09d9d736 100644 --- a/feeluown/gui/components/avatar.py +++ b/feeluown/gui/components/avatar.py @@ -82,6 +82,9 @@ def contextMenuEvent(self, e) -> None: menu.exec_(e.globalPos()) def on_provider_ui_login_event(self, provider_ui, event): + current_pvd_ui = self._app.current_pvd_ui_mgr.get() + if current_pvd_ui == provider_ui and event == 2: + return if event in (1, 2): run_afn(self.show_pvd_ui_current_user) run_afn( @@ -90,12 +93,13 @@ def on_provider_ui_login_event(self, provider_ui, event): ) def on_pvd_ui_selected(self, pvd_ui): - self._app.current_pvd_ui_mgr.set(pvd_ui) if isinstance(pvd_ui, UISupportsLoginEvent): pvd_ui.login_event.connect(self.on_provider_ui_login_event) if isinstance(pvd_ui, UISupportsLoginOrGoHome): pvd_ui.login_or_go_home() - run_afn(self.show_pvd_ui_current_user) + # Set current provider ui at the very last. + # Must not set it before handling login event. + self._app.current_pvd_ui_mgr.set(pvd_ui) def on_provider_selected(self, provider: ProviderUiItem): self._app.current_pvd_ui_mgr.set_item(provider) diff --git a/feeluown/gui/provider_ui.py b/feeluown/gui/provider_ui.py index e6714dd907..214f584563 100644 --- a/feeluown/gui/provider_ui.py +++ b/feeluown/gui/provider_ui.py @@ -23,14 +23,24 @@ class NavBtn: @runtime_checkable class UISupportsLoginOrGoHome(Protocol): - @abstractmethod def login_or_go_home(self): - ... + """This method is called when the avatar is clicked. + + Typically, ProviderUI can implement this method as follows: + - When no user is logged in, ProviderUI MAY show a login dialog. + - When a user is logged in, ProviderUI MAY show the homepage. + At the same time, ProviderUI MAY emit a login success event. + """ @runtime_checkable class UISupportsLoginEvent(Protocol): + """ + When the user is logged in, ProviderUI MAY emit a login success event. + This allows FeelUOwn to perform certain actions based on this event, + for example, fetching and show the user's playlist. + """ @property @abstractmethod