qqmusic-api-python 0.6.6__tar.gz → 0.6.8__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 (198) hide show
  1. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.gitignore +1 -0
  2. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/AGENTS.md +21 -1
  3. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/PKG-INFO +6 -1
  4. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/README.md +3 -0
  5. qqmusic_api_python-0.6.8/docs/coding.md +431 -0
  6. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/release-notes.md +54 -0
  7. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/tutorial/client.md +13 -6
  8. qqmusic_api_python-0.6.8/docs/tutorial/download.md +124 -0
  9. qqmusic_api_python-0.6.8/docs/tutorial/error-handling.md +69 -0
  10. qqmusic_api_python-0.6.8/docs/tutorial/login.md +171 -0
  11. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/tutorial/start.md +16 -12
  12. qqmusic_api_python-0.6.8/examples/upload_file.py +33 -0
  13. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/pyproject.toml +9 -0
  14. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/__init__.py +9 -1
  15. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/__init__.py +8 -0
  16. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/client.py +27 -8
  17. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/exceptions.py +77 -1
  18. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/album.py +7 -7
  19. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/base.py +29 -29
  20. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/comment.py +56 -56
  21. qqmusic_api_python-0.6.8/qqmusic_api/models/helper.py +177 -0
  22. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/login.py +14 -2
  23. qqmusic_api_python-0.6.8/qqmusic_api/models/lyric.py +34 -0
  24. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/mv.py +2 -2
  25. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/private_message.py +32 -30
  26. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/recommend.py +14 -14
  27. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/search.py +13 -13
  28. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/singer.py +51 -51
  29. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/song.py +49 -49
  30. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/songlist.py +4 -4
  31. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/top.py +29 -27
  32. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/user.py +133 -93
  33. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/__init__.py +2 -0
  34. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/_base.py +15 -0
  35. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/comment.py +6 -2
  36. qqmusic_api_python-0.6.8/qqmusic_api/modules/helper.py +84 -0
  37. qqmusic_api_python-0.6.8/qqmusic_api/modules/helper_utils.py +280 -0
  38. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/login.py +42 -7
  39. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/private_message.py +34 -31
  40. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/search.py +2 -0
  41. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/singer.py +2 -0
  42. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/song.py +4 -0
  43. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/songlist.py +8 -8
  44. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/user.py +174 -14
  45. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/utils/device.py +5 -0
  46. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/utils/qimei.py +12 -4
  47. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_login.py +49 -5
  48. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_lyric.py +1 -7
  49. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_user.py +25 -0
  50. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/uv.lock +112 -0
  51. qqmusic_api_python-0.6.8/web/Dockerfile +44 -0
  52. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/README.md +10 -3
  53. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/app.py +2 -2
  54. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/song.py +2 -0
  55. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/router_factory.py +1 -0
  56. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/zensical.toml +8 -3
  57. qqmusic_api_python-0.6.6/docs/coding.md +0 -342
  58. qqmusic_api_python-0.6.6/qqmusic_api/models/lyric.py +0 -41
  59. qqmusic_api_python-0.6.6/web/Dockerfile +0 -23
  60. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.agents/skills/pydantic/SKILL.md +0 -0
  61. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.agents/skills/python-standards/SKILL.md +0 -0
  62. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.agents/skills/tarsio/SKILL.md +0 -0
  63. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.agents/skills/tarsio/references/api-reference.md +0 -0
  64. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.agents/skills/uv-package-manager/SKILL.md +0 -0
  65. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.dockerignore +0 -0
  66. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  67. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  68. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  69. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  70. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/renovate.json +0 -0
  71. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/workflows/checking.yaml +0 -0
  72. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/workflows/docs.yml +0 -0
  73. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/workflows/release.yml +0 -0
  74. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.github/workflows/testing.yml +0 -0
  75. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/.markdownlint-cli2.yaml +0 -0
  76. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/CLAUDE.md +0 -0
  77. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/LICENSE +0 -0
  78. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/assets/qq-music.svg +0 -0
  79. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/cliff.toml +0 -0
  80. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/contributing.md +0 -0
  81. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/index.md +0 -0
  82. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/core/client.md +0 -0
  83. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/core/exception.md +0 -0
  84. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/core/pagination.md +0 -0
  85. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/core/request.md +0 -0
  86. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/core/versioning.md +0 -0
  87. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/album.md +0 -0
  88. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/base.md +0 -0
  89. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/comment.md +0 -0
  90. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/login.md +0 -0
  91. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/lyric.md +0 -0
  92. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/mv.md +0 -0
  93. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/recommend.md +0 -0
  94. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/request.md +0 -0
  95. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/search.md +0 -0
  96. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/singer.md +0 -0
  97. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/song.md +0 -0
  98. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/songlist.md +0 -0
  99. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/top.md +0 -0
  100. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/model/user.md +0 -0
  101. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/album.md +0 -0
  102. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/comment.md +0 -0
  103. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/login.md +0 -0
  104. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/login_utils.md +0 -0
  105. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/lyric.md +0 -0
  106. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/mv.md +0 -0
  107. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/private_message.md +0 -0
  108. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/recommend.md +0 -0
  109. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/search.md +0 -0
  110. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/singer.md +0 -0
  111. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/song.md +0 -0
  112. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/songlist.md +0 -0
  113. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/top.md +0 -0
  114. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/reference/modules/user.md +0 -0
  115. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/tutorial/credential.md +0 -0
  116. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/tutorial/pagination.md +0 -0
  117. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/docs/tutorial/web.md +0 -0
  118. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/examples/download_song.py +0 -0
  119. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/examples/get_all_sheets.py +0 -0
  120. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/examples/phone_login.py +0 -0
  121. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/examples/private_message.py +0 -0
  122. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/examples/qrcode_login.py +0 -0
  123. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/prek.toml +0 -0
  124. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/algorithms/__init__.py +0 -0
  125. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/algorithms/sign.py +0 -0
  126. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/algorithms/tripledes.py +0 -0
  127. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/pagination.py +0 -0
  128. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/request.py +0 -0
  129. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/core/versioning.py +0 -0
  130. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/__init__.py +0 -0
  131. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/_validator.py +0 -0
  132. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/models/request.py +0 -0
  133. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/album.py +0 -0
  134. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/login_utils.py +0 -0
  135. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/lyric.py +0 -0
  136. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/mv.py +0 -0
  137. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/recommend.py +0 -0
  138. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/modules/top.py +0 -0
  139. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/utils/__init__.py +0 -0
  140. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/utils/common.py +0 -0
  141. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/qqmusic_api/utils/mqtt.py +0 -0
  142. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/scripts/ag-1.py +0 -0
  143. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/conftest.py +0 -0
  144. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_album.py +0 -0
  145. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_comment.py +0 -0
  146. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_login_utils.py +0 -0
  147. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_mv.py +0 -0
  148. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_private_message.py +0 -0
  149. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_recommend.py +0 -0
  150. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_search.py +0 -0
  151. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_singer.py +0 -0
  152. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_song.py +0 -0
  153. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_songlist.py +0 -0
  154. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/tests/test_top.py +0 -0
  155. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/.gitignore +0 -0
  156. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/accounts.example.toml +0 -0
  157. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/config.example.toml +0 -0
  158. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/docker-compose.yml +0 -0
  159. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/requirements.txt +0 -0
  160. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/run.py +0 -0
  161. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/__init__.py +0 -0
  162. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/auth.py +0 -0
  163. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/cache.py +0 -0
  164. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/config.py +0 -0
  165. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/credential_store.py +0 -0
  166. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/deps.py +0 -0
  167. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/response.py +0 -0
  168. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/core/security.py +0 -0
  169. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/__init__.py +0 -0
  170. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/comment.py +0 -0
  171. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/login.py +0 -0
  172. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/mv.py +0 -0
  173. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/singer.py +0 -0
  174. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/song.py +0 -0
  175. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/modules/songlist.py +0 -0
  176. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/__init__.py +0 -0
  177. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/_helpers.py +0 -0
  178. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/album.py +0 -0
  179. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/comment.py +0 -0
  180. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/login.py +0 -0
  181. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/lyric.py +0 -0
  182. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/mv.py +0 -0
  183. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/recommend.py +0 -0
  184. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/search.py +0 -0
  185. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/singer.py +0 -0
  186. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/songlist.py +0 -0
  187. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/top.py +0 -0
  188. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routes/user.py +0 -0
  189. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/__init__.py +0 -0
  190. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/docstrings.py +0 -0
  191. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/executor.py +0 -0
  192. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/params.py +0 -0
  193. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/src/routing/route_types.py +0 -0
  194. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/tests/test_web_core.py +0 -0
  195. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/tests/test_web_docstrings.py +0 -0
  196. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/tests/test_web_enums.py +0 -0
  197. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/tests/test_web_route_validation.py +0 -0
  198. {qqmusic_api_python-0.6.6 → qqmusic_api_python-0.6.8}/web/tests/test_web_routes.py +0 -0
@@ -13,6 +13,7 @@ device.json
13
13
  # AI
14
14
  .ccb/
15
15
  docs/superpowers/
16
+ .omo/
16
17
 
17
18
  # Distribution / packaging
18
19
  .Python
@@ -47,8 +47,28 @@
47
47
  * 新增页面必须同步更新 `zensical.toml` 的 `nav`。
48
48
  * 文档构建工具实际使用 `zensical`,配置文件是 `zensical.toml`。
49
49
 
50
+ ## Release workflow
51
+
52
+ 1. 更新 `qqmusic_api/__init__.py` 中的 `__version__` 为待发布版本。
53
+ 2. 提交版本号变更:
54
+
55
+ ```bash
56
+ git add qqmusic_api/__init__.py
57
+ git commit -m "🧹 chore(release): x.x.x"
58
+ ```
59
+
60
+ 3. 在**该提交上**打 tag 并推送:
61
+
62
+ ```bash
63
+ git tag v0.x.x
64
+ git push origin v0.x.x
65
+ ```
66
+
67
+ 4. CI 自动执行:
68
+ * **release.yml**:`uv build` → `uv publish`(PyPI)→ 创建 GitHub Release(git-cliff 自动生成 release body)
69
+ * **docs.yml**(release published 后触发):更新 `docs/release-notes.md` → 导出 `web/requirements.txt` → commit → 构建文档站 → 部署 GitHub Pages
70
+
50
71
  ## Agent behavior
51
72
 
52
- * 每次回答都以 `皇上启奏:` 开头。
53
73
  * **核心规约**:遵循 `docs/contributing.md` 中的详细规约。**在执行任务前,必须完整阅读该指南以确保合规。**
54
74
  * 仅在明确要求时,才能 `git commit` 或 `git push`。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qqmusic-api-python
3
- Version: 0.6.6
3
+ Version: 0.6.8
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/
@@ -37,6 +37,8 @@ Requires-Dist: paho-mqtt>=2.1.0
37
37
  Requires-Dist: pydantic>=2.13.3
38
38
  Requires-Dist: tarsio>=0.5.1
39
39
  Requires-Dist: typing-extensions>=4.12.2
40
+ Provides-Extra: upload
41
+ Requires-Dist: cos-python-sdk-v5>=1.9.44; extra == 'upload'
40
42
  Description-Content-Type: text/markdown
41
43
 
42
44
  <div align="center">
@@ -56,6 +58,9 @@ Description-Content-Type: text/markdown
56
58
  <a href="https://github.com/l-1124/QQMusicApi/actions/workflows/testing.yml">
57
59
  <img src="https://github.com/l-1124/QQMusicApi/actions/workflows/testing.yml/badge.svg?branch=main" alt="Testing">
58
60
  </a>
61
+ <a href="https://deepwiki.com/luren-dc/QQMusicApi">
62
+ <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
63
+ </a>
59
64
  </div>
60
65
 
61
66
  ---
@@ -15,6 +15,9 @@
15
15
  <a href="https://github.com/l-1124/QQMusicApi/actions/workflows/testing.yml">
16
16
  <img src="https://github.com/l-1124/QQMusicApi/actions/workflows/testing.yml/badge.svg?branch=main" alt="Testing">
17
17
  </a>
18
+ <a href="https://deepwiki.com/luren-dc/QQMusicApi">
19
+ <img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki">
20
+ </a>
18
21
  </div>
19
22
 
20
23
  ---
@@ -0,0 +1,431 @@
1
+ # API 编写指南
2
+
3
+ `qqmusic_api` 采用 `Client + ApiModule + Request` 的结构:
4
+
5
+ * `Client` 负责网络发送、平台信息和凭证。
6
+ * `ApiModule` 负责声明接口参数,并返回可 `await` 的 `Request`。
7
+
8
+ ## 调用流程图
9
+
10
+ ### 单请求
11
+
12
+ ```text
13
+ 模块方法
14
+ -> self._build_request(...)
15
+ -> Request
16
+ -> await request
17
+ -> Client.execute(request)
18
+ -> Client.request_api(...) (根据 request.is_jce 分发改用 JCE 或 JSON 协议)
19
+ -> Client._build_result(...)
20
+ -> 返回原始 dict / TarsDict 或 Pydantic 模型
21
+ ```
22
+
23
+ ### 批量并发请求
24
+
25
+ ```text
26
+ 多个模块方法
27
+ -> self._build_request(...)
28
+ -> Request 列表
29
+ -> Client.gather(requests)
30
+ -> 按协议、平台、公共参数和凭证分组
31
+ -> 每组按 batch_size 拆分为批量请求
32
+ -> 依次调用 Client.request_api(..., lazy=True) 生成响应任务
33
+ -> 使用客户端内部的 multiplexed AsyncSession 并发执行这些任务(self._session.gather)
34
+ -> 按 req_n 解析每个响应项
35
+ -> 按输入顺序返回结果
36
+ ```
37
+
38
+ `gather` 的分组边界由 `Request._group_key` 决定。只有协议类型、显式平台、公共参数和凭证相同的请求才会合并到同一个批量请求中。
39
+
40
+ ## 编写新的 API
41
+
42
+ ### 添加新模块
43
+
44
+ 1. 在 `qqmusic_api/modules/` 下创建新文件,例如 `foo.py`。
45
+ 2. 定义模块类,继承 `ApiModule`。
46
+ 3. 在 `Client` 中注册为 `@cached_property`。
47
+
48
+ ```python
49
+ # qqmusic_api/modules/foo.py
50
+ from ._base import ApiModule
51
+
52
+
53
+ class FooApi(ApiModule):
54
+ """Foo 相关 API."""
55
+
56
+ def get_something(self, id: int):
57
+ """获取某项数据."""
58
+ return self._build_request(
59
+ module="music.foo.Svc",
60
+ method="GetSomething",
61
+ param={"id": id},
62
+ )
63
+ ```
64
+
65
+ ```python
66
+ # qqmusic_api/core/client.py
67
+ from functools import cached_property
68
+
69
+ class Client:
70
+ @cached_property
71
+ def foo(self) -> "FooApi":
72
+ from ..modules.foo import FooApi
73
+ return FooApi(self)
74
+ ```
75
+
76
+ ### 添加新的请求方法
77
+
78
+ API 方法返回 `Request` 对象,不直接发起请求。使用 `self._build_request(...)` 工厂方法构建:
79
+
80
+ ```python
81
+ def get_detail(self, song_id: int):
82
+ """获取歌曲详情."""
83
+ return self._build_request(
84
+ module="music.songDetail", # 接口所属模块
85
+ method="GetDetail", # 方法名
86
+ param={"songid": song_id}, # 业务参数
87
+ )
88
+ ```
89
+
90
+ 对于非标准 CGI 接口(如直接 GET 请求),使用 `self._request(...)`:
91
+
92
+ ```python
93
+ async def quick_search(self, keyword: str) -> dict[str, Any]:
94
+ """快速搜索 (直接返回解析后的 JSON 数据)."""
95
+ resp = await self._request(
96
+ "GET",
97
+ "https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg",
98
+ params={"key": keyword},
99
+ )
100
+ resp.raise_for_status()
101
+ return resp.json()["data"]
102
+ ```
103
+
104
+ ### `_build_request` 参数说明
105
+
106
+ | 参数 | 类型 | 说明 |
107
+ |------------------|-----------------------------|-----------------------------------------------------------|
108
+ | `module` | `str` | 接口所属模块名 |
109
+ | `method` | `str` | 方法名 |
110
+ | `param` | `dict` | 业务参数 |
111
+ | `response_model` | `type[BaseModel]` 或 `None` | 响应模型,为 None 时返回原始 dict |
112
+ | `comm` | `dict` 或 `None` | 附加的公共参数 |
113
+ | `override_comm` | `bool` | 为 True 时 `comm` 完全替代自动生成的参数;为 False 时合并 |
114
+ | `credential` | `Credential` 或 `None` | 覆盖本次请求的凭证 |
115
+ | `platform` | `Platform` 或 `None` | 覆盖本次请求的平台 |
116
+ | `is_jce` | `bool` | 是否作为 JCE (Tars) 二进制协议发送 |
117
+ | `preserve_bool` | `bool` | 是否保留布尔值原样(默认转为 0/1 整型) |
118
+ | `sign` | `bool` | 是否对请求进行签名 |
119
+ | `pager_meta` | `PagerMeta` 或 `None` | 分页元数据,提供后返回 `PaginatedRequest` |
120
+ | `refresh_meta` | `RefreshMeta` 或 `None` | 换一批元数据,提供后返回 `RefreshableRequest` |
121
+
122
+ ### `client.request` 参数说明
123
+
124
+ `client.request` 是底层 HTTP 请求方法,自动装配凭证 Cookies 和平台 User-Agent:
125
+
126
+ | 参数 | 类型 | 说明 |
127
+ |--------------|------------------------|----------------------------------------------------------------------------------:|
128
+ | `method` | `str` | HTTP 方法,如 `"GET"`、`"POST"` |
129
+ | `url` | `str` | 请求地址 |
130
+ | `credential` | `Credential` 或 `None` | 覆盖本次请求的凭证,默认使用客户端凭证 |
131
+ | `platform` | `Platform` 或 `None` | 覆盖本次请求的平台,默认使用客户端平台 |
132
+ | `lazy` | `bool` | 是否延迟发送请求(用于批量并发) |
133
+ | `**kwargs` | | 透传给底层 `niquests` 的参数(`params`、`json`、`data`、`headers`、`cookies` 等) |
134
+
135
+ !!! note
136
+
137
+ `client.request` 返回的是原始 `niquests.Response` 对象,需要手动解析响应。而 `_build_request` 返回的 `Request` 对象支持 `await`,会自动完成响应验证和模型解析。
138
+
139
+ 常见用法:
140
+
141
+ ```python
142
+ # GET 请求
143
+ resp = await client.request("GET", "https://example.com/api", params={"key": "value"})
144
+
145
+ # POST JSON
146
+ resp = await client.request("POST", "https://example.com/api", json={"key": "value"})
147
+
148
+ # POST form data
149
+ resp = await client.request("POST", "https://example.com/api", data={"key": "value"})
150
+
151
+ # 自定义 headers
152
+ resp = await client.request("GET", "https://example.com/api", headers={"X-Custom": "value"})
153
+
154
+ # 覆盖凭证
155
+ resp = await client.request("GET", "https://example.com/api", credential=my_credential)
156
+ ```
157
+
158
+ ## 响应模型
159
+
160
+ ### 基础用法
161
+
162
+ 每个响应模型都应继承 `models.request.Response`:
163
+
164
+ ```python
165
+ from pydantic import Field
166
+
167
+ from .request import Response
168
+
169
+
170
+ class MyResponse(Response):
171
+ """我的响应模型."""
172
+
173
+ name: str
174
+ count: int
175
+ ```
176
+
177
+ `Response` 基类配置了 `frozen=True`(不可变)和 `extra="ignore"`(忽略多余字段)。
178
+
179
+ ### JSONPath 字段映射
180
+
181
+ 可以通过 `Field(json_schema_extra={"jsonpath": ...})` 声明字段的 JSONPath 映射路径,自动从嵌套响应中提取数据:
182
+
183
+ ```python
184
+ class SonglistMeta(Response):
185
+ """歌单元数据示例."""
186
+
187
+ id: int = Field(json_schema_extra={"jsonpath": "$.result.tid"})
188
+ dirid: int = Field(json_schema_extra={"jsonpath": "$.result.dirId"})
189
+ name: str = Field(json_schema_extra={"jsonpath": "$.result.dirName"})
190
+ ```
191
+
192
+ 对于列表字段,使用 `[*]` 通配符:
193
+
194
+ ```python
195
+ class CommentListResponse(Response):
196
+ """评论列表响应."""
197
+
198
+ comments: list[Comment] = Field(
199
+ default_factory=list,
200
+ json_schema_extra={"jsonpath": "$.commentlist[*]"},
201
+ )
202
+ ```
203
+
204
+ ### 字段别名
205
+
206
+ Pydantic 的 `validation_alias` 支持多别名兼容:
207
+
208
+ ```python
209
+ class Singer(Response):
210
+ """歌手信息."""
211
+
212
+ id: int = Field(
213
+ default=-1,
214
+ validation_alias=AliasChoices("id", "singerID", "singerId", "SingerID"),
215
+ )
216
+ mid: str = Field(
217
+ default="",
218
+ validation_alias=AliasChoices("mid", "singerMid", "singerMID"),
219
+ )
220
+ ```
221
+
222
+ ### 需登录的接口
223
+
224
+ 需要登录的接口通过 `_build_request` 的 `require_login` 参数校验凭证:
225
+
226
+ ```python
227
+ def get_vip_info(self, *, credential: Credential | None = None):
228
+ """获取 VIP 信息."""
229
+ return self._build_request(
230
+ module="VipLogin.VipLoginInter",
231
+ method="vip_login_base",
232
+ param={},
233
+ credential=credential,
234
+ response_model=UserVipInfoResponse,
235
+ require_login=True,
236
+ )
237
+ ```
238
+
239
+ > 若接口需要凭证对象的字段来构建请求参数,
240
+ > 仍可显式调用 `_require_login` 获取凭证对象。
241
+
242
+ ## 翻页与换一批
243
+
244
+ ### 连续翻页
245
+
246
+ 通过 `pager_meta` 声明连续翻页能力,返回的请求对象会暴露 `.paginate()`:
247
+
248
+ ```python
249
+ from ..core.pagination import OffsetStrategy, PagerMeta, ResponseAdapter
250
+
251
+
252
+ def get_detail(self, songlist_id: int, num: int = 10, page: int = 1):
253
+ """获取歌单详情."""
254
+ return self._build_request(
255
+ module="music.srfDissInfo.DissInfo",
256
+ method="CgiGetDiss",
257
+ param={
258
+ "disstid": songlist_id,
259
+ "song_begin": num * (page - 1),
260
+ "song_num": num,
261
+ },
262
+ response_model=GetSonglistDetailResponse,
263
+ pager_meta=PagerMeta(
264
+ strategy=OffsetStrategy(offset_key="song_begin", page_size_key="song_num"),
265
+ adapter=ResponseAdapter(
266
+ has_more_flag="hasmore",
267
+ total="total",
268
+ count=lambda response: len(response.songs),
269
+ ),
270
+ ),
271
+ )
272
+ ```
273
+
274
+ ### 换一批
275
+
276
+ 通过 `refresh_meta` 声明换一批能力,返回的请求对象会暴露 `.refresh()`:
277
+
278
+ ```python
279
+ from ..core.pagination import BatchRefreshStrategy, RefreshMeta, ResponseAdapter
280
+
281
+
282
+ def get_related_mv(self, songid: int, last_mvid: str | None = None):
283
+ """获取歌曲相关 MV."""
284
+ return self._build_request(
285
+ module="MvService.MvInfoProServer",
286
+ method="GetSongRelatedMv",
287
+ param={"songid": str(songid), "songtype": 1, "lastmvid": last_mvid or 0},
288
+ response_model=GetRelatedMvResponse,
289
+ refresh_meta=RefreshMeta(
290
+ strategy=BatchRefreshStrategy(refresh_key="lastmvid"),
291
+ adapter=ResponseAdapter(
292
+ has_more_flag="has_more",
293
+ cursor=lambda response: response.mv[-1].id if response.mv else None,
294
+ ),
295
+ ),
296
+ )
297
+ ```
298
+
299
+ ### 内置策略速查
300
+
301
+ | 策略 | 适用场景 | 关键参数 |
302
+ |----------------------------------|-------------:|---------------------------------|
303
+ | `PageStrategy` | 页码递增 | `page_key` |
304
+ | `OffsetStrategy` | 偏移量滑窗 | `offset_key` + `page_size_key` |
305
+ | `CursorStrategy` | 响应游标回写 | `cursor_key` |
306
+ | `MultiFieldContinuationStrategy` | 多字段续翻 | 自定义 `build_next_params` 函数 |
307
+ | `BatchRefreshStrategy` | 换一批 | `refresh_key` |
308
+
309
+ `pager_meta` 与 `refresh_meta` 不能同时声明。
310
+
311
+ ## JCE (Tars) 协议
312
+
313
+ 部分接口使用 JCE 二进制协议而非 JSON。通过 `is_jce=True` 启用:
314
+
315
+ ```python
316
+ def get_something(self):
317
+ """获取数据 (JCE 协议)."""
318
+ return self._build_request(
319
+ module="music.foo.Svc",
320
+ method="GetSomething",
321
+ param={0: "value"}, # JCE 使用整数 key
322
+ is_jce=True,
323
+ )
324
+ ```
325
+
326
+ JCE 协议的响应会自动解码为 `TarsDict`。
327
+
328
+ ## 请求签名
329
+
330
+ 部分接口需要对请求体进行签名。通过 `sign=True` 启用:
331
+
332
+ ```python
333
+ def get_sheet(self, mid: str):
334
+ """获取曲谱."""
335
+ return self._build_request(
336
+ module="music.mir.SheetMusicSvr",
337
+ method="GetMoreSheetMusic",
338
+ param={"songMid": mid},
339
+ sign=True,
340
+ )
341
+ ```
342
+
343
+ 签名后请求会发送到 `musics.fcg` 而非 `musicu.fcg`,并在 URL 参数中附加 `_`(时间戳)和 `sign`。
344
+
345
+ ## 公共参数 `comm`
346
+
347
+ 默认情况下,`comm` 参数由 `VersionPolicy.build_comm()` 自动生成。可以通过 `comm` 附加额外参数:
348
+
349
+ ```python
350
+ # 合并到自动生成的 comm 中(默认行为)
351
+ self._build_request(
352
+ ...,
353
+ comm={"extra_key": "value"},
354
+ )
355
+ ```
356
+
357
+ 使用 `override_comm=True` 完全替代自动生成的参数:
358
+
359
+ ```python
360
+ self._build_request(
361
+ ...,
362
+ comm={
363
+ "g_tk": 5381,
364
+ "uin": "",
365
+ "format": "json",
366
+ "inCharset": "utf-8",
367
+ "outCharset": "utf-8",
368
+ "notice": 0,
369
+ "needNewCode": 1,
370
+ },
371
+ override_comm=True,
372
+ )
373
+ ```
374
+
375
+ ## 编写测试
376
+
377
+ 测试文件放在 `tests/` 下,按模块命名(如 `test_song.py`)。
378
+
379
+ ### 基本格式
380
+
381
+ ```python
382
+ """歌曲模块测试."""
383
+
384
+ import pytest
385
+
386
+ from qqmusic_api import Client
387
+
388
+
389
+ async def test_query_song(client: Client) -> None:
390
+ """测试根据 ID 查询歌曲."""
391
+ result = await client.song.query_song(["003w2xz20QlUZt"])
392
+ assert result.tracks
393
+ assert result.tracks[0].name
394
+ ```
395
+
396
+ ### 使用 parametrize
397
+
398
+ ```python
399
+ @pytest.mark.parametrize("page", [1, 2])
400
+ async def test_general_search(client: Client, page: int) -> None:
401
+ """测试综合搜索翻页."""
402
+ result = await client.search.general_search("周杰伦", page=page)
403
+ assert result.song.items is not None
404
+ ```
405
+
406
+ ### 需要登录的测试
407
+
408
+ 使用 `authenticated_client` fixture:
409
+
410
+ ```python
411
+ async def test_get_vip_info(authenticated_client: Client) -> None:
412
+ """测试获取 VIP 信息."""
413
+ result = await authenticated_client.user.get_vip_info()
414
+ assert result.vip_flag is not None
415
+ ```
416
+
417
+ ### 测试分页
418
+
419
+ ```python
420
+ async def test_search_paginate(client: Client) -> None:
421
+ """测试搜索分页."""
422
+ pager = client.search.search_by_type("周杰伦", num=5).paginate(limit=2)
423
+
424
+ assert pager.has_more() is True
425
+ first_page = await pager.next()
426
+ assert pager.has_more() is True
427
+ second_page = await pager.next()
428
+
429
+ assert first_page.song
430
+ assert second_page.song
431
+ ```
@@ -1,4 +1,58 @@
1
1
 
2
+ ## [[0.6.7](https://github.com/L-1124/QQMusicApi/compare/v0.6.6..v0.6.7)] - 2026-06-17
3
+
4
+ ### 功能更新
5
+
6
+ * **(login)** 新增登录异常子类和错误码映射 ([0ef9645](https://github.com/L-1124/QQMusicApi/commit/0ef9645806c9778cfa6214dd60fa56644568c276)) by [@jinzhongjia](https://github.com/jinzhongjia) in [#269](https://github.com/L-1124/QQMusicApi/pull/269)
7
+ * **(qimei)** 增加 24 小时过期重新获取逻辑 ([05aed29](https://github.com/L-1124/QQMusicApi/commit/05aed29096dff31b7d0cbb26ccc66ec50da38bdc)) by [@L-1124](https://github.com/L-1124)
8
+ * **(web)** 添加 has_sheet 路由 ([9e7a143](https://github.com/L-1124/QQMusicApi/commit/9e7a1439ff597ae43a4ef99d88ec08ee32889b9a)) by [@L-1124](https://github.com/L-1124)
9
+
10
+ ### 文档更新
11
+
12
+ * **(coding)** 重写 API 编写指南,补充开发细节 ([9db46de](https://github.com/L-1124/QQMusicApi/commit/9db46def73ec6c2d9826c4a15bc2eb7ba9ed0f37)) by [@L-1124](https://github.com/L-1124)
13
+ * 为固定请求平台的 API 补充 docstring 说明 ([aba712e](https://github.com/L-1124/QQMusicApi/commit/aba712e56a7485b4184941480c05f370cd53c548)) by [@L-1124](https://github.com/L-1124)
14
+ * 完善快速开始文档并新增多篇核心教程 ([d6143cd](https://github.com/L-1124/QQMusicApi/commit/d6143cdc047ebeb4963b061680a21103ba3d58d4)) by [@L-1124](https://github.com/L-1124)
15
+
16
+ ### 贡献者
17
+
18
+ * @L-1124
19
+ * @jinzhongjia [#269](https://github.com/L-1124/QQMusicApi/pull/269)
20
+ * @github-actions[bot]
21
+ * @renovate[bot]
22
+
23
+ ## [[0.6.6](https://github.com/L-1124/QQMusicApi/compare/v0.6.5..v0.6.6)] - 2026-06-13
24
+
25
+ ### Bug 修复
26
+
27
+ * **(song)** 修复 get_sheet 获取无曲谱歌曲时触发异常的问题 ([f47a643](https://github.com/L-1124/QQMusicApi/commit/f47a643e956ef52a532b0017ea8365cb2537593d)) by [@L-1124](https://github.com/L-1124)
28
+ * **(web)** 修复评论适配器与凭证锁内存泄漏,优化基础设施 ([66a6cc4](https://github.com/L-1124/QQMusicApi/commit/66a6cc4901b1acd99b0c4541f88a1d8e0a9b0888)) by [@L-1124](https://github.com/L-1124)
29
+
30
+ ### Revert
31
+
32
+ * **(models)** 回退 BaseModel 额外字段处理策略为 extra='ignore' ([f6691e0](https://github.com/L-1124/QQMusicApi/commit/f6691e078b87a45f5178d7a018f9a1bd0d5e391a)) by [@L-1124](https://github.com/L-1124)
33
+
34
+ ### 功能更新
35
+
36
+ * **(client)** 支持 zzc 请求签名 ([eb4eb66](https://github.com/L-1124/QQMusicApi/commit/eb4eb66f5c20c2adbe430bbfb11140d0431d48d5)) by [@L-1124](https://github.com/L-1124)
37
+ * **(core)** 支持在使用 allow_error_codes 放行时强制解析模型 ([fac2a71](https://github.com/L-1124/QQMusicApi/commit/fac2a71bfb2f2ea700d59215a439fc65b40461f2)) by [@L-1124](https://github.com/L-1124)
38
+ * **(core)** 支持通过 override_comm 彻底替代通用请求载荷 ([72edb4f](https://github.com/L-1124/QQMusicApi/commit/72edb4f3cc96a063643f2d58b92d41722ad95e8f)) by [@L-1124](https://github.com/L-1124)
39
+ * **(song)** 添加新的曲谱相关 API和相关示例 ([9c461db](https://github.com/L-1124/QQMusicApi/commit/9c461dbdff15acf804ae047a7bc827cd6b1e7dd5)) by [@L-1124](https://github.com/L-1124)
40
+ * **(song)** 支持 HasSheetMusic 接口检查歌曲是否有曲谱 ([94723ff](https://github.com/L-1124/QQMusicApi/commit/94723ffda911f74d680f7f661e9436bba74c3612)) by [@L-1124](https://github.com/L-1124)
41
+ * **(web)** 补充 requirements.txt ([d806214](https://github.com/L-1124/QQMusicApi/commit/d80621477635f6e0ad3589116cbb97c75e31dc6c)) by [@L-1124](https://github.com/L-1124)
42
+
43
+ ### 性能优化
44
+
45
+ * **(qrc)** 优化自定义 3DES 解密性能并补充测试 ([0b808a5](https://github.com/L-1124/QQMusicApi/commit/0b808a5537643f2c3bd0ef94e5c72263ec378bb8)) by [@L-1124](https://github.com/L-1124)
46
+
47
+ ### 构建配置
48
+
49
+ * **(web)** 在 Dockerfile 运行命令中添加 --no-sync 防止容器运行期同步 dev 依赖 ([cf1fbc5](https://github.com/L-1124/QQMusicApi/commit/cf1fbc5523c83b21734d82763a89aef450825674)) by [@L-1124](https://github.com/L-1124)
50
+
51
+ ### 贡献者
52
+
53
+ * @L-1124
54
+ * @github-actions[bot]
55
+
2
56
  ## [[0.6.5](https://github.com/L-1124/QQMusicApi/compare/v0.6.4..v0.6.5)] - 2026-06-12
3
57
 
4
58
  ### Bug 修复
@@ -76,10 +76,6 @@ client = Client(credential=credential)
76
76
 
77
77
  默认的请求平台是 `android`,如果需要可以在初始化时覆盖:
78
78
 
79
- !!! note
80
-
81
- 部分 API 的请求平台是固定的,无法覆盖。
82
-
83
79
  ```python
84
80
  import asyncio
85
81
 
@@ -91,10 +87,21 @@ async def main():
91
87
  ...
92
88
 
93
89
 
94
- asyncio.run(_main())
95
-
90
+ asyncio.run(main())
96
91
  ```
97
92
 
93
+ 支持的平台:
94
+
95
+ | 平台 | `Platform` 值 | 说明 |
96
+ | ------ | -------------- | ------ |
97
+ | Android | `Platform.ANDROID` | 默认,大部分接口使用 |
98
+ | Desktop | `Platform.DESKTOP` | QQ 音乐桌面端 |
99
+ | Web | `Platform.WEB` | QQ 音乐网页端 |
100
+
101
+ !!! note
102
+
103
+ 部分接口的请求平台是固定的,传入 `platform` 参数不会生效。例如 `get_detail` 固定使用 Web 平台,`send_authcode` 固定使用 Android 平台。
104
+
98
105
  ## 设备信息
99
106
 
100
107
  可通过 `device_path` 参数指定设备信息文件的路径进行持久化存储: