qqmusic-api-python 0.5.1__tar.gz → 0.5.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/workflows/docs.yml +1 -1
  2. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/PKG-INFO +1 -1
  3. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/release-notes.md +22 -0
  4. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/tutorial/pagination.md +28 -1
  5. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/pyproject.toml +3 -0
  6. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/__init__.py +1 -1
  7. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/pagination.py +17 -1
  8. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/album.py +7 -1
  9. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/user.py +1 -1
  10. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/user.py +1 -1
  11. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_comment.py +11 -5
  12. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_search.py +14 -11
  13. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.agents/skills/pydantic/SKILL.md +0 -0
  14. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.agents/skills/python-standards/SKILL.md +0 -0
  15. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.agents/skills/tarsio/SKILL.md +0 -0
  16. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.agents/skills/tarsio/references/api-reference.md +0 -0
  17. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.agents/skills/uv-package-manager/SKILL.md +0 -0
  18. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  19. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  20. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  21. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  22. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/renovate.json +0 -0
  23. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/workflows/checking.yaml +0 -0
  24. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/workflows/release.yml +0 -0
  25. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.github/workflows/testing.yml +0 -0
  26. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.gitignore +0 -0
  27. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/.markdownlint-cli2.yaml +0 -0
  28. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/AGENTS.md +0 -0
  29. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/LICENSE +0 -0
  30. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/README.md +0 -0
  31. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/assets/qq-music.svg +0 -0
  32. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/cliff.toml +0 -0
  33. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/coding.md +0 -0
  34. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/contributing.md +0 -0
  35. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/index.md +0 -0
  36. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/core/client.md +0 -0
  37. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/core/exception.md +0 -0
  38. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/core/pagination.md +0 -0
  39. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/core/request.md +0 -0
  40. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/core/versioning.md +0 -0
  41. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/album.md +0 -0
  42. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/base.md +0 -0
  43. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/comment.md +0 -0
  44. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/login.md +0 -0
  45. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/lyric.md +0 -0
  46. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/mv.md +0 -0
  47. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/recommend.md +0 -0
  48. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/request.md +0 -0
  49. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/search.md +0 -0
  50. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/singer.md +0 -0
  51. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/song.md +0 -0
  52. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/songlist.md +0 -0
  53. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/top.md +0 -0
  54. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/model/user.md +0 -0
  55. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/album.md +0 -0
  56. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/comment.md +0 -0
  57. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/login.md +0 -0
  58. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/login_utils.md +0 -0
  59. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/lyric.md +0 -0
  60. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/mv.md +0 -0
  61. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/recommend.md +0 -0
  62. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/search.md +0 -0
  63. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/singer.md +0 -0
  64. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/song.md +0 -0
  65. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/songlist.md +0 -0
  66. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/top.md +0 -0
  67. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/reference/modules/user.md +0 -0
  68. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/tutorial/client.md +0 -0
  69. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/tutorial/credential.md +0 -0
  70. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/docs/tutorial/start.md +0 -0
  71. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/examples/download_song.py +0 -0
  72. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/examples/phone_login.py +0 -0
  73. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/examples/qrcode_login.py +0 -0
  74. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/prek.toml +0 -0
  75. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/algorithms/__init__.py +0 -0
  76. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/algorithms/sign.py +0 -0
  77. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/algorithms/tripledes.py +0 -0
  78. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/__init__.py +0 -0
  79. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/client.py +0 -0
  80. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/exceptions.py +0 -0
  81. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/request.py +0 -0
  82. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/core/versioning.py +0 -0
  83. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/__init__.py +0 -0
  84. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/base.py +0 -0
  85. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/comment.py +0 -0
  86. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/login.py +0 -0
  87. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/lyric.py +0 -0
  88. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/mv.py +0 -0
  89. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/recommend.py +0 -0
  90. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/request.py +0 -0
  91. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/search.py +0 -0
  92. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/singer.py +0 -0
  93. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/song.py +0 -0
  94. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/songlist.py +0 -0
  95. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/models/top.py +0 -0
  96. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/__init__.py +0 -0
  97. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/_base.py +0 -0
  98. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/album.py +0 -0
  99. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/comment.py +0 -0
  100. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/login.py +0 -0
  101. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/login_utils.py +0 -0
  102. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/lyric.py +0 -0
  103. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/mv.py +0 -0
  104. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/recommend.py +0 -0
  105. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/search.py +0 -0
  106. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/singer.py +0 -0
  107. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/song.py +0 -0
  108. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/songlist.py +0 -0
  109. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/modules/top.py +0 -0
  110. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/utils/__init__.py +0 -0
  111. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/utils/common.py +0 -0
  112. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/utils/device.py +0 -0
  113. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/utils/mqtt.py +0 -0
  114. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/qqmusic_api/utils/qimei.py +0 -0
  115. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/scripts/ag-1.py +0 -0
  116. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/conftest.py +0 -0
  117. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_album.py +0 -0
  118. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_login.py +0 -0
  119. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_login_utils.py +0 -0
  120. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_lyric.py +0 -0
  121. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_mv.py +0 -0
  122. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_recommend.py +0 -0
  123. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_singer.py +0 -0
  124. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_song.py +0 -0
  125. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_songlist.py +0 -0
  126. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_top.py +0 -0
  127. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/tests/test_user.py +0 -0
  128. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/uv.lock +0 -0
  129. {qqmusic_api_python-0.5.1 → qqmusic_api_python-0.5.2}/zensical.toml +0 -0
@@ -53,7 +53,7 @@ jobs:
53
53
  - name: Build with zensical
54
54
  run: uv run zensical build
55
55
  - name: Upload artifact
56
- uses: actions/upload-pages-artifact@v4
56
+ uses: actions/upload-pages-artifact@v5
57
57
  with:
58
58
  path: ./site
59
59
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qqmusic-api-python
3
- Version: 0.5.1
3
+ Version: 0.5.2
4
4
  Summary: QQ音乐API封装库
5
5
  Project-URL: documentation, https://l-1124.github.io/QQMusicApi/
6
6
  Project-URL: homepage, https://l-1124.github.io/QQMusicApi/
@@ -3,6 +3,27 @@
3
3
 
4
4
  ### 文档更新
5
5
 
6
+ * **(pagination)** 修正分页示例错误 ([c310450](https://github.com/L-1124/QQMusicApi/commit/c31045021034ce130136a17b458091c456998d53)) by [@L-1124](https://github.com/L-1124)
7
+
8
+ ### 贡献者
9
+
10
+ * @L-1124
11
+ * @github-actions[bot]
12
+
13
+ ## [[0.5.1](https://github.com/L-1124/QQMusicApi/compare/v0.5.0..v0.5.1)] - 2026-04-13
14
+
15
+ ### 功能更新
16
+
17
+ * 获取歌曲文件支持传入歌曲类型 ([a2ad367](https://github.com/L-1124/QQMusicApi/commit/a2ad3675ac56a501f8e08e761e12c68bf6155a98)) by [@L-1124](https://github.com/L-1124)
18
+ * [**breaking**] 重构歌曲文件获取逻辑,支持获取特殊类型的歌曲文件 ([5e31a48](https://github.com/L-1124/QQMusicApi/commit/5e31a4888cf3d4818b3cd59861ffc4d883c4ca1a)) by [@L-1124](https://github.com/L-1124)
19
+ * 接口请求支持更方便的下一页、换一批请求 ([98693f8](https://github.com/L-1124/QQMusicApi/commit/98693f86995df7a62ca705a46643afffb3306e4a)) by [@L-1124](https://github.com/L-1124) in [#235](https://github.com/L-1124/QQMusicApi/pull/235)
20
+
21
+ ### 功能重构
22
+
23
+ * **(login)** 优化 MQTT 登录链路并替换 HTTP 重试实现 ([244e000](https://github.com/L-1124/QQMusicApi/commit/244e000c08dce6beb3ab46c7d266c361515b4b20)) by [@L-1124](https://github.com/L-1124) in [#237](https://github.com/L-1124/QQMusicApi/pull/237)
24
+
25
+ ### 文档更新
26
+
6
27
  * **(index)** 修正首页使用示例 ([ebafd9c](https://github.com/L-1124/QQMusicApi/commit/ebafd9cfc119c35e8b7a8fa16cd60abe81657707)) by [@L-1124](https://github.com/L-1124)
7
28
  * 添加缺少的模块文档 ([376970e](https://github.com/L-1124/QQMusicApi/commit/376970ececc30e876342548ddacded06e48112d7)) by [@L-1124](https://github.com/L-1124)
8
29
  * 更新 index.md ([d8e3668](https://github.com/L-1124/QQMusicApi/commit/d8e3668fdfb8e4766f8cf0cbc0e3bb9eece0bfd0)) by [@L-1124](https://github.com/L-1124)
@@ -10,6 +31,7 @@
10
31
  ### 贡献者
11
32
 
12
33
  * @L-1124
34
+ * @renovate[bot] [#238](https://github.com/L-1124/QQMusicApi/pull/238)
13
35
  * @github-actions[bot]
14
36
 
15
37
  ## [[0.5.0](https://github.com/L-1124/QQMusicApi/compare/v0.4.1..v0.5.0)] - 2026-04-02
@@ -19,15 +19,42 @@ from qqmusic_api import Client
19
19
  async def main() -> None:
20
20
  async with Client() as client:
21
21
  pager = client.search.search_by_type("周杰伦", num=5).paginate(limit=3)
22
+ page_number = 1
22
23
 
23
24
  async for page in pager:
24
- print(page.nextpage)
25
+ print(f"第 {page_number} 页")
25
26
  print(len(page.song))
27
+ page_number += 1
28
+
29
+ asyncio.run(main())
30
+ ```
31
+
32
+ ## Pager 手动逐页拉取
33
+
34
+ 如果你希望自行控制何时请求下一页, 可以配合 `has_more()` 与 `next()` 使用。`has_more()` 只读取分页器当前状态, 不会主动发起网络请求。
35
+
36
+ > `next()` 与 `async for` 的终止行为一致: 没有更多结果时会抛出 `StopAsyncIteration`。
37
+
38
+ ```python
39
+ import asyncio
40
+
41
+ from qqmusic_api import Client
42
+
43
+
44
+ async def main() -> None:
45
+ async with Client() as client:
46
+ pager = client.comment.get_hot_comments(102065756, page_size=5).paginate(limit=2)
47
+
48
+ while pager.has_more():
49
+ page = await pager.next()
50
+ print(len(page.comments))
26
51
 
27
52
 
28
53
  asyncio.run(main())
29
54
  ```
30
55
 
56
+ 在第一页尚未请求前, 只要分页器未耗尽且未达到 `limit`, `has_more()` 就会返回 `True`。当上游响应已经明确没有下一页, 或者你已经达到 `limit`, `has_more()` 会变为 `False`。
57
+
31
58
  ## Pager 返回值
32
59
 
33
60
  分页器每次迭代返回的,仍然是该接口原本的响应模型。
@@ -103,6 +103,9 @@ asyncio_mode = "auto"
103
103
  line-length = 120
104
104
  extend-exclude = ["docs"]
105
105
 
106
+ [tool.pyright]
107
+ typeCheckingMode = "basic"
108
+
106
109
  [tool.ruff.lint]
107
110
  extend-select = [
108
111
  "A",
@@ -14,7 +14,7 @@ from .core.exceptions import (
14
14
  from .core.versioning import Platform
15
15
  from .models.request import Credential
16
16
 
17
- __version__ = "0.5.1"
17
+ __version__ = "0.5.2"
18
18
 
19
19
  __all__ = [
20
20
  "ApiError",
@@ -434,18 +434,34 @@ class ResponsePager(_BaseResponseAdvancer[RequestResultT], AsyncIterator[Request
434
434
  self._limit = limit
435
435
  self._yielded_count = 0
436
436
 
437
+ def _can_advance(self) -> bool:
438
+ """返回当前分页器是否还能继续产出下一页."""
439
+ if self._next_request is None:
440
+ return False
441
+ if self._limit is None:
442
+ return True
443
+ return self._yielded_count < self._limit
444
+
437
445
  def __aiter__(self) -> AsyncIterator[RequestResultT]:
438
446
  """返回分页器自身, 以支持 `async for` 迭代."""
439
447
  return self
440
448
 
441
449
  async def __anext__(self) -> RequestResultT:
442
450
  """获取并返回下一页响应."""
443
- if self._limit is not None and self._yielded_count >= self._limit:
451
+ if not self._can_advance():
444
452
  raise StopAsyncIteration
445
453
  response = await self._advance()
446
454
  self._yielded_count += 1
447
455
  return response
448
456
 
457
+ async def next(self) -> RequestResultT:
458
+ """获取并返回下一页响应."""
459
+ return await self.__anext__()
460
+
461
+ def has_more(self) -> bool:
462
+ """返回当前分页器是否还能继续产出下一页."""
463
+ return self._can_advance()
464
+
449
465
  def _get_meta(self, request: "PaginatedRequest[RequestResultT]") -> PagerMeta:
450
466
  """读取分页请求对应的连续翻页元数据."""
451
467
  return request.get_pager_meta()
@@ -1,6 +1,6 @@
1
1
  """Album API 返回模型定义."""
2
2
 
3
- from pydantic import Field
3
+ from pydantic import Field, field_validator
4
4
 
5
5
  from .base import Album, Singer, Song
6
6
  from .request import Response
@@ -70,3 +70,9 @@ class GetAlbumSongResponse(Response):
70
70
  album_mid: str = Field(alias="albumMid")
71
71
  total_num: int = Field(alias="totalNum")
72
72
  song_list: list[Song] = Field(default_factory=list, json_schema_extra={"jsonpath": "$.songList[*].songInfo"})
73
+
74
+ @field_validator("song_list", mode="before")
75
+ @classmethod
76
+ def _coerce_song_list(cls, value: list[dict] | dict) -> list[dict]:
77
+ """将上游返回的单个歌曲信息统一规整为列表."""
78
+ return [value] if isinstance(value, dict) else value
@@ -126,7 +126,7 @@ class UserFavSonglistResponse(Response):
126
126
  total: int
127
127
  hasmore: int
128
128
  hide: bool
129
- playlists: list[UserFavSonglistItem] = Field(json_schema_extra={"jsonpath": "$.v_list[*]"})
129
+ playlists: list[UserFavSonglistItem] = Field(json_schema_extra={"jsonpath": "$.v_list"})
130
130
  deleted_ids: list[int] = Field(alias="v_delTids")
131
131
  failed_ids: list[int] = Field(alias="v_failTids")
132
132
 
@@ -46,7 +46,7 @@ class UserApi(ApiModule):
46
46
 
47
47
  Args:
48
48
  euin: 加密后的 UIN.
49
- credential: 可选的登录凭证;未传入时优先使用客户端当前凭证,
49
+ credential: 可选的登录凭证; 未传入时优先使用客户端当前凭证,
50
50
  若客户端凭证不可用则自动使用占位凭证.
51
51
  """
52
52
  target_credential = self._resolve_placeholder_credential(credential)
@@ -39,13 +39,19 @@ async def test_get_moment_comments(client: Client) -> None:
39
39
 
40
40
 
41
41
  async def test_get_hot_comments_paginate(client: Client) -> None:
42
- """测试热评列表分页能力."""
42
+ """测试热评列表支持手动逐页拉取."""
43
43
  pager = client.comment.get_hot_comments(102065756, page_num=1, page_size=5).paginate(limit=2)
44
- pages = [page async for page in pager]
45
44
 
46
- assert len(pages) == 2
47
- assert pages[0].comments
48
- assert pages[1].comments
45
+ assert pager.has_more() is True
46
+ first_page = await pager.next()
47
+ assert pager.has_more() is True
48
+ second_page = await pager.next()
49
+
50
+ assert first_page.comments
51
+ assert second_page.comments
52
+ assert pager.has_more() is False
53
+ with pytest.raises(StopAsyncIteration):
54
+ await pager.next()
49
55
 
50
56
 
51
57
  async def test_get_moment_comments_paginate(client: Client) -> None:
@@ -60,14 +60,17 @@ async def test_search_by_type_with_int(client: Client) -> None:
60
60
 
61
61
 
62
62
  async def test_search_by_type_paginate(client: Client) -> None:
63
- """测试按类型搜索的分页能力."""
64
- # 测试分页迭代 (取前两页)
65
- pager = client.search.search_by_type("周杰伦", num=5, page=1).paginate()
66
- pages = []
67
- async for page in pager:
68
- pages.append(page)
69
- if len(pages) >= 2:
70
- break
71
-
72
- assert len(pages) == 2
73
- assert pages[0].nextpage == 2
63
+ """测试搜索分页支持 next 与 has_more."""
64
+ pager = client.search.search_by_type("周杰伦", num=5, page=1).paginate(limit=2)
65
+
66
+ assert pager.has_more() is True
67
+ first_page = await pager.next()
68
+ assert pager.has_more() is True
69
+ second_page = await pager.next()
70
+
71
+ assert first_page.song
72
+ assert second_page.song
73
+ assert first_page.nextpage == 2
74
+ assert pager.has_more() is False
75
+ with pytest.raises(StopAsyncIteration):
76
+ await pager.next()