qqmusic-api-python 0.8.0__tar.gz → 0.8.1__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 (233) hide show
  1. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/PKG-INFO +1 -1
  2. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/release-notes.md +60 -0
  3. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/credential.md +2 -2
  4. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/web.md +4 -4
  5. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/__init__.py +1 -1
  6. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/executor.py +1 -1
  7. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/transport.py +15 -3
  8. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/request.py +4 -0
  9. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/user.py +1 -1
  10. qqmusic_api_python-0.8.1/qqmusic_api/py.typed +0 -0
  11. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/app.py +2 -0
  12. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/auth.py +1 -3
  13. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/config.py +1 -1
  14. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/credential_pool.py +2 -2
  15. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/credential_store.py +5 -10
  16. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/response.py +8 -2
  17. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/login.py +3 -1
  18. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/executor.py +1 -2
  19. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.agents/skills/pydantic/SKILL.md +0 -0
  20. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.agents/skills/python-standards/SKILL.md +0 -0
  21. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.agents/skills/uv-package-manager/SKILL.md +0 -0
  22. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.dockerignore +0 -0
  23. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
  24. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  25. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
  26. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  27. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/renovate.json +0 -0
  28. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/workflows/checking.yaml +0 -0
  29. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/workflows/docs.yml +0 -0
  30. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/workflows/release.yml +0 -0
  31. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.github/workflows/testing.yml +0 -0
  32. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.gitignore +0 -0
  33. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/.markdownlint-cli2.yaml +0 -0
  34. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/AGENTS.md +0 -0
  35. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/CLAUDE.md +0 -0
  36. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/LICENSE +0 -0
  37. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/README.md +0 -0
  38. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/assets/qq-music.svg +0 -0
  39. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/cliff.toml +0 -0
  40. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/coding.md +0 -0
  41. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/contributing.md +0 -0
  42. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/index.md +0 -0
  43. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/core/client.md +0 -0
  44. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/core/exception.md +0 -0
  45. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/core/pagination.md +0 -0
  46. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/core/request.md +0 -0
  47. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/core/versioning.md +0 -0
  48. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/album.md +0 -0
  49. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/base.md +0 -0
  50. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/comment.md +0 -0
  51. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/helper.md +0 -0
  52. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/login.md +0 -0
  53. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/lyric.md +0 -0
  54. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/mv.md +0 -0
  55. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/private_message.md +0 -0
  56. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/recommend.md +0 -0
  57. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/request.md +0 -0
  58. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/search.md +0 -0
  59. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/singer.md +0 -0
  60. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/song.md +0 -0
  61. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/songlist.md +0 -0
  62. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/sound_power.md +0 -0
  63. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/top.md +0 -0
  64. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/model/user.md +0 -0
  65. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/album.md +0 -0
  66. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/comment.md +0 -0
  67. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/helper.md +0 -0
  68. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/helper_utils.md +0 -0
  69. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/login.md +0 -0
  70. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/login_utils.md +0 -0
  71. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/lyric.md +0 -0
  72. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/mv.md +0 -0
  73. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/private_message.md +0 -0
  74. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/recommend.md +0 -0
  75. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/search.md +0 -0
  76. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/singer.md +0 -0
  77. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/song.md +0 -0
  78. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/songlist.md +0 -0
  79. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/sound_power.md +0 -0
  80. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/top.md +0 -0
  81. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/reference/modules/user.md +0 -0
  82. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/client.md +0 -0
  83. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/download.md +0 -0
  84. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/error-handling.md +0 -0
  85. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/login.md +0 -0
  86. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/pagination.md +0 -0
  87. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/docs/tutorial/start.md +0 -0
  88. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/download_song.py +0 -0
  89. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/get_all_sheets.py +0 -0
  90. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/phone_login.py +0 -0
  91. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/private_message.py +0 -0
  92. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/qrcode_login.py +0 -0
  93. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/sound_power.py +0 -0
  94. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/examples/upload_file.py +0 -0
  95. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/prek.toml +0 -0
  96. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/pyproject.toml +0 -0
  97. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/algorithms/__init__.py +0 -0
  98. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/algorithms/sign.py +0 -0
  99. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/algorithms/tripledes.py +0 -0
  100. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/__init__.py +0 -0
  101. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/client.py +0 -0
  102. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/endpoint.py +0 -0
  103. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/engine.py +0 -0
  104. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/exceptions.py +0 -0
  105. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/pagination.py +0 -0
  106. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/request.py +0 -0
  107. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/response.py +0 -0
  108. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/core/versioning.py +0 -0
  109. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/__init__.py +0 -0
  110. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/_validator.py +0 -0
  111. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/album.py +0 -0
  112. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/base.py +0 -0
  113. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/comment.py +0 -0
  114. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/helper.py +0 -0
  115. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/login.py +0 -0
  116. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/lyric.py +0 -0
  117. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/mv.py +0 -0
  118. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/private_message.py +0 -0
  119. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/recommend.py +0 -0
  120. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/search.py +0 -0
  121. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/singer.py +0 -0
  122. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/song.py +0 -0
  123. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/songlist.py +0 -0
  124. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/sound_power.py +0 -0
  125. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/top.py +0 -0
  126. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/models/user.py +0 -0
  127. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/__init__.py +0 -0
  128. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/_base.py +0 -0
  129. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/album.py +0 -0
  130. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/comment.py +0 -0
  131. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/helper.py +0 -0
  132. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/helper_utils.py +0 -0
  133. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/login.py +0 -0
  134. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/login_utils.py +0 -0
  135. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/lyric.py +0 -0
  136. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/mv.py +0 -0
  137. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/private_message.py +0 -0
  138. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/recommend.py +0 -0
  139. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/search.py +0 -0
  140. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/singer.py +0 -0
  141. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/song.py +0 -0
  142. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/songlist.py +0 -0
  143. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/sound_power.py +0 -0
  144. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/modules/top.py +0 -0
  145. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/__init__.py +0 -0
  146. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/android_session.py +0 -0
  147. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/common.py +0 -0
  148. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/device.py +0 -0
  149. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/mqtt.py +0 -0
  150. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/qqmusic_api/utils/qimei.py +0 -0
  151. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/scripts/ag-1.py +0 -0
  152. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/conftest.py +0 -0
  153. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/kernel_contract.py +0 -0
  154. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_album.py +0 -0
  155. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_android_session.py +0 -0
  156. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_client.py +0 -0
  157. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_comment.py +0 -0
  158. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_device.py +0 -0
  159. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_endpoint.py +0 -0
  160. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_engine.py +0 -0
  161. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_executor.py +0 -0
  162. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_login.py +0 -0
  163. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_login_engine.py +0 -0
  164. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_login_utils.py +0 -0
  165. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_lyric.py +0 -0
  166. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_mv.py +0 -0
  167. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_pagination.py +0 -0
  168. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_private_message.py +0 -0
  169. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_qimei.py +0 -0
  170. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_recommend.py +0 -0
  171. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_response.py +0 -0
  172. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_search.py +0 -0
  173. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_singer.py +0 -0
  174. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_song.py +0 -0
  175. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_songlist.py +0 -0
  176. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_sound_power.py +0 -0
  177. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_top.py +0 -0
  178. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_transport.py +0 -0
  179. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/test_user.py +0 -0
  180. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/typing/test_build_request.py +0 -0
  181. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/typing/test_client_typing.py +0 -0
  182. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/tests/typing/test_endpoint_typing.py +0 -0
  183. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/uv.lock +0 -0
  184. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/.gitignore +0 -0
  185. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/Dockerfile +0 -0
  186. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/README.md +0 -0
  187. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/accounts.example.toml +0 -0
  188. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/config.example.toml +0 -0
  189. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/docker-compose.example.yml +0 -0
  190. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/requirements.txt +0 -0
  191. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/run.py +0 -0
  192. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/__init__.py +0 -0
  193. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/cache.py +0 -0
  194. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/coalesce.py +0 -0
  195. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/deps.py +0 -0
  196. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/error_mapping.py +0 -0
  197. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/core/security.py +0 -0
  198. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/__init__.py +0 -0
  199. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/comment.py +0 -0
  200. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/login.py +0 -0
  201. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/mv.py +0 -0
  202. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/singer.py +0 -0
  203. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/song.py +0 -0
  204. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/modules/songlist.py +0 -0
  205. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/__init__.py +0 -0
  206. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/_helpers.py +0 -0
  207. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/album.py +0 -0
  208. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/comment.py +0 -0
  209. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/lyric.py +0 -0
  210. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/mv.py +0 -0
  211. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/recommend.py +0 -0
  212. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/search.py +0 -0
  213. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/singer.py +0 -0
  214. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/song.py +0 -0
  215. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/songlist.py +0 -0
  216. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/sound_power.py +0 -0
  217. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/top.py +0 -0
  218. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routes/user.py +0 -0
  219. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/__init__.py +0 -0
  220. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/adapter_registry.py +0 -0
  221. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/docstrings.py +0 -0
  222. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/modules.py +0 -0
  223. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/params.py +0 -0
  224. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/route_types.py +0 -0
  225. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/src/routing/router_factory.py +0 -0
  226. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/conftest.py +0 -0
  227. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_core.py +0 -0
  228. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_docstrings.py +0 -0
  229. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_engine_services.py +0 -0
  230. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_enums.py +0 -0
  231. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_route_validation.py +0 -0
  232. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/web/tests/test_web_routes.py +0 -0
  233. {qqmusic_api_python-0.8.0 → qqmusic_api_python-0.8.1}/zensical.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: qqmusic-api-python
3
- Version: 0.8.0
3
+ Version: 0.8.1
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/
@@ -1,4 +1,64 @@
1
1
 
2
+ ## [[0.8.0](https://github.com/L-1124/QQMusicApi/compare/v0.7.3..v0.8.0)] - 2026-10-04
3
+
4
+ ### Bug 修复
5
+
6
+ * **(core)** 修复请求分页提取器的参数克隆冲突 ([e74d00b](https://github.com/L-1124/QQMusicApi/commit/e74d00b6cc6274676adb9855902234c6a9a9fcb1)) by [@L-1124](https://github.com/L-1124)
7
+ * **(tests)** 修复 disable_parse 移除后的测试残留并清理装饰性框线 ([39fc259](https://github.com/L-1124/QQMusicApi/commit/39fc259bdeefb3fd9f740d678a380da59e98f8da)) by [@L-1124](https://github.com/L-1124)
8
+ * **(web)** 未捕获异常统一返回 JSON 形状的 500 响应 ([95e5ab4](https://github.com/L-1124/QQMusicApi/commit/95e5ab44c79e7503df969677e5848b5b376efafa)) by [@L-1124](https://github.com/L-1124)
9
+ * **(web)** 屏蔽上游 5xx 异常细节并修正凭证快照的阻塞调用 ([2d384b0](https://github.com/L-1124/QQMusicApi/commit/2d384b021d0082dc2715c84884b36d29801ca342)) by [@L-1124](https://github.com/L-1124)
10
+ * **(web)** 修复池凭证过期判定与刷新未同锁导致的重复登录 ([4426508](https://github.com/L-1124/QQMusicApi/commit/442650810e9fe43d0a646b4dfc8f76696dbb55e5)) by [@L-1124](https://github.com/L-1124)
11
+ * **(web)** 修复调用方 Cookie 凭证被刷新并写回共享池的问题 ([4aeab21](https://github.com/L-1124/QQMusicApi/commit/4aeab216a26b873707c817457321b225a8e9d169)) by [@L-1124](https://github.com/L-1124)
12
+
13
+ ### 功能更新
14
+
15
+ * **(core)** Android comm 参数补充注入 traceid ([84cc613](https://github.com/L-1124/QQMusicApi/commit/84cc6131a1cd44939d63edcdde5b3b554211bc88)) by [@L-1124](https://github.com/L-1124)
16
+ * **(core)** 提升全局 Android 协议版本为 20.9.0.8 ([6ce5d7e](https://github.com/L-1124/QQMusicApi/commit/6ce5d7ef6c45cea392173c33e493d98f0f3d2913)) by [@L-1124](https://github.com/L-1124)
17
+ * **(core)** 引入声明式 Endpoint 与无客户端网关 ([116e7fd](https://github.com/L-1124/QQMusicApi/commit/116e7fdb701f6d261ac913c3636b56f188c17ced)) by [@L-1124](https://github.com/L-1124) in [#304](https://github.com/L-1124/QQMusicApi/pull/304)
18
+ * **(core)** 优化 comm 参数与设备标识语义 ([072011a](https://github.com/L-1124/QQMusicApi/commit/072011a5f5d9d60181148d79981701862906d6dc)) by [@L-1124](https://github.com/L-1124)
19
+ * **(core)** 解耦设备缓存并完善并发控制 ([2eb66c4](https://github.com/L-1124/QQMusicApi/commit/2eb66c4c1651d6f525015c8c4bf6cb72e963c814)) by [@L-1124](https://github.com/L-1124)
20
+ * **(core)** [**breaking**] 引入统一请求内核与显式流式读取 ([bc09d1c](https://github.com/L-1124/QQMusicApi/commit/bc09d1c60b1ffb093255938d63fa5a197af9939f)) by [@L-1124](https://github.com/L-1124) in [#303](https://github.com/L-1124/QQMusicApi/pull/303)
21
+ * **(device)** 完善 Android 设备档案生成 ([4c67b50](https://github.com/L-1124/QQMusicApi/commit/4c67b50bfd4a03fde786e63b4fef0a587f3f4d12)) by [@L-1124](https://github.com/L-1124)
22
+ * **(device)** 优化设备生成与 QIMEI 参数 ([f207f82](https://github.com/L-1124/QQMusicApi/commit/f207f8281e63da2b4fac4391dd7dbe10c527d68d)) by [@L-1124](https://github.com/L-1124)
23
+ * **(sound_power)** 新增音响力与听歌榜模块及 Web 路由 ([514fc3f](https://github.com/L-1124/QQMusicApi/commit/514fc3f4f1357d0b73d95f6fd37f65ec9b6d86b7)) by [@L-1124](https://github.com/L-1124)
24
+ * **(web)** 缓存未命中引入请求合并与上游失败标记熔断 ([807421d](https://github.com/L-1124/QQMusicApi/commit/807421db284db78e034d3abb1948228462d7d6e5)) by [@L-1124](https://github.com/L-1124)
25
+
26
+ ### 功能重构
27
+
28
+ * **(album)** 迁移 AlbumApi 端点至 @cgi_endpoint 并更新 Web 路由 ([7522cea](https://github.com/L-1124/QQMusicApi/commit/7522ceadc69c4be3a3aa188b45f9f3d752109797)) by [@L-1124](https://github.com/L-1124)
29
+ * **(comment)** 迁移 CommentApi 端点至 @cgi_endpoint 并更新 Web 路由 ([1565743](https://github.com/L-1124/QQMusicApi/commit/1565743030dc6bed7c2574ffc37ecb4aec93a919)) by [@L-1124](https://github.com/L-1124)
30
+ * **(core)** 让 CgiRequestData.param 默认为空字典并移除冗余空参数 ([55f7b01](https://github.com/L-1124/QQMusicApi/commit/55f7b014ea4b118d2520278db8ffda900a871bf2)) by [@L-1124](https://github.com/L-1124)
31
+ * **(core)** 彻底移除 disable_parse 选项并更新端点声明范式文档 ([5cf1a06](https://github.com/L-1124/QQMusicApi/commit/5cf1a0645f7fec6523ec05a725ab1ef161d577d1)) by [@L-1124](https://github.com/L-1124)
32
+ * **(core)** 彻底分离端点元数据与运行期覆盖契约 ([46a1a2e](https://github.com/L-1124/QQMusicApi/commit/46a1a2e143698bbf77e3c8b318ff334c491f4755)) by [@L-1124](https://github.com/L-1124)
33
+ * **(core)** 为端点装饰器增加分页类型重载与通用契约校验 ([f443e65](https://github.com/L-1124/QQMusicApi/commit/f443e6561ff5331d7023d2b538a9ace9dd1e8d6e)) by [@L-1124](https://github.com/L-1124)
34
+ * **(lyric)** 迁移 LyricApi 端点至 @cgi_endpoint 并更新 Web 路由 ([e12ae87](https://github.com/L-1124/QQMusicApi/commit/e12ae875b1170d3eb7fbcf7724a801439807166f)) by [@L-1124](https://github.com/L-1124)
35
+ * **(modules)** 为各模块端点声明 item_type 与 pager 契约并清理测试 ([8308052](https://github.com/L-1124/QQMusicApi/commit/8308052cfeee23c8bb78425d28d0bc6d997d8375)) by [@L-1124](https://github.com/L-1124)
36
+ * **(mv)** 迁移 MvApi 端点至 @cgi_endpoint 并更新 Web 路由 ([d2e383c](https://github.com/L-1124/QQMusicApi/commit/d2e383cbcb8e304931afc04bf76167cce365cc1d)) by [@L-1124](https://github.com/L-1124)
37
+ * **(recommend)** 迁移 RecommendApi 端点至 @cgi_endpoint 并更新 Web 路由 ([b97c043](https://github.com/L-1124/QQMusicApi/commit/b97c0436907e51a3ca489797e95f37de53cb1dde)) by [@L-1124](https://github.com/L-1124)
38
+ * **(search)** 迁移 SearchApi 端点至 @cgi_endpoint 并更新 Web 路由 ([25fe3eb](https://github.com/L-1124/QQMusicApi/commit/25fe3ebeac8f65119d7b5ab3bc3f3e681c4a1b01)) by [@L-1124](https://github.com/L-1124)
39
+ * **(singer)** [**breaking**] 移除 get_name_special_display 并合并至 get_info ([e293aa3](https://github.com/L-1124/QQMusicApi/commit/e293aa320f316ae9e654f90503c8a4b9186b0b91)) by [@L-1124](https://github.com/L-1124)
40
+ * **(singer)** 迁移 SingerApi 端点至 @cgi_endpoint 并更新 Web 路由 ([79af270](https://github.com/L-1124/QQMusicApi/commit/79af2704002f53f29024eb0aabd82d9917b798d4)) by [@L-1124](https://github.com/L-1124)
41
+ * **(song)** 迁移 SongApi 端点至 @cgi_endpoint 并更新 Web 路由 ([8c08868](https://github.com/L-1124/QQMusicApi/commit/8c08868cd72c633ac023635fcf4f28c58a25576d)) by [@L-1124](https://github.com/L-1124)
42
+ * **(songlist)** 迁移 SonglistApi 端点至 @cgi_endpoint 并更新 Web 路由 ([ba50d18](https://github.com/L-1124/QQMusicApi/commit/ba50d1864e69d91e6ce896cf47085745e93bed7a)) by [@L-1124](https://github.com/L-1124)
43
+ * **(top)** 迁移 TopApi 端点至 @cgi_endpoint 并更新 Web 路由 ([e2a1fee](https://github.com/L-1124/QQMusicApi/commit/e2a1fee9c7a3d5193a3b2a37b6f6b4a6bf5348de)) by [@L-1124](https://github.com/L-1124)
44
+ * **(user)** 迁移 UserApi 端点至 @cgi_endpoint 并更新 Web 路由 ([49921f6](https://github.com/L-1124/QQMusicApi/commit/49921f600cb9ede33990bffa1d85ef502c985896)) by [@L-1124](https://github.com/L-1124)
45
+ * **(web)** [**breaking**] 优化 web 端参数声明,减少冗余 ([ba95861](https://github.com/L-1124/QQMusicApi/commit/ba95861ee9391f5b5f60f89caa8d4de4af160c8b)) by [@L-1124](https://github.com/L-1124)
46
+ * **(web)** 在路由注册器中增加 Web 模块白名单校验 ([9b0bc65](https://github.com/L-1124/QQMusicApi/commit/9b0bc6590ab597db25b5da378298dfd2a6817881)) by [@L-1124](https://github.com/L-1124)
47
+
48
+ ### 性能优化
49
+
50
+ * **(qimei)** 优化设备特征计算与静态参数缓存 ([e19fdf2](https://github.com/L-1124/QQMusicApi/commit/e19fdf2f2e8f25a2b3bb24c03b7db16b90a832f6)) by [@L-1124](https://github.com/L-1124)
51
+
52
+ ### 文档更新
53
+
54
+ * **(coding)** 补充声明式端点撰写指南并更新架构概览与调用流程 ([866bffb](https://github.com/L-1124/QQMusicApi/commit/866bffb6b20ef37ba81b36c7476164f9a8b8e556)) by [@L-1124](https://github.com/L-1124)
55
+ * **(examples)** 新增音响力查询与听歌时长上报示例 ([a408059](https://github.com/L-1124/QQMusicApi/commit/a40805982fd53c2db45db1e878aa9ab6934141af)) by [@L-1124](https://github.com/L-1124)
56
+
57
+ ### 贡献者
58
+
59
+ * @L-1124
60
+ * @github-actions[bot]
61
+
2
62
  ## [[0.7.3](https://github.com/L-1124/QQMusicApi/compare/v0.7.2..v0.7.3)] - 2026-09-13
3
63
 
4
64
  ### Bug 修复
@@ -40,7 +40,7 @@ asyncio.run(main())
40
40
 
41
41
  ## 单次请求覆盖
42
42
 
43
- 如果你不想把凭证绑定到整个 `Client`,需要 `Crential` 的接口都支持使用 `credential` 参数进行单次请求覆盖。
43
+ 如果你不想把凭证绑定到整个 `Client`,需要登录态的接口都支持使用 `credential` 参数进行单次请求覆盖。
44
44
 
45
45
  ```python
46
46
  import asyncio
@@ -76,7 +76,7 @@ async def main() -> None:
76
76
  refresh_token="xxx",
77
77
  access_token="xxx",
78
78
  )
79
- await credential.refresh(client)
79
+ credential = await client.login.refresh_credential(credential)
80
80
  print(credential.musicid, credential.musickey)
81
81
 
82
82
  asyncio.run(main())
@@ -1,11 +1,11 @@
1
- # Web 服务
1
+ # QQMusic API Web 服务
2
2
 
3
3
  Web 服务将 QQMusicApi 暴露为 HTTP API。
4
4
 
5
5
  ## 1. 安装
6
6
 
7
7
  ```bash
8
- git clone https://github.com/luren-dc/QQMusicApi
8
+ git clone https://github.com/L-1124/QQMusicApi
9
9
  cd QQMusicApi
10
10
  uv sync --group web
11
11
  ```
@@ -15,12 +15,12 @@ uv sync --group web
15
15
  ## 2. 启动服务
16
16
 
17
17
  ```bash
18
- uv run python web/run.py
18
+ uv run --no-sync web/run.py
19
19
  ```
20
20
 
21
21
  ## 3. 查看 API 文档
22
22
 
23
- 打开 [http://localhost:8000/docs](http://localhost:8000/docs) 可以查看所有可用接口。
23
+ 默认监听 `127.0.0.1:8080`。打开 [http://localhost:8080/docs](http://localhost:8080/docs) 可以查看所有可用接口,Swagger UI 与 ReDoc 分别位于 `/swagger` 与 `/redoc`。
24
24
 
25
25
  ## 4. 认证方式
26
26
 
@@ -23,7 +23,7 @@ from .core.exceptions import (
23
23
  from .core.versioning import Platform
24
24
  from .models.request import Credential
25
25
 
26
- __version__ = "0.8.0"
26
+ __version__ = "0.8.1"
27
27
 
28
28
  __all__ = [
29
29
  "ApiDataError",
@@ -126,7 +126,7 @@ class CgiExecutor:
126
126
  results[call.index] = exc
127
127
  continue
128
128
  raise
129
- if request.require_login and not bool(call.scope.credential.musicid and call.scope.credential.musickey):
129
+ if request.require_login and not call.scope.credential.is_valid():
130
130
  exc = CredentialInvalidError("请求需要登录, 未提供有效的登录凭证")
131
131
  if return_exceptions:
132
132
  results[call.index] = exc
@@ -11,7 +11,13 @@ from niquests import AsyncSession, AsyncTokenBucketLimiter, RetryConfiguration
11
11
  from niquests import PreparedRequest as NiquestsPreparedRequest
12
12
  from niquests.exceptions import RequestException, Timeout
13
13
  from niquests.models import Response
14
- from niquests.typing import AsyncHookType, ProxyType, TLSClientCertType, TLSVerifyType
14
+ from niquests.typing import (
15
+ AsyncHookType,
16
+ ProxyType,
17
+ TimeoutType,
18
+ TLSClientCertType,
19
+ TLSVerifyType,
20
+ )
15
21
 
16
22
  from .exceptions import NetworkError, TimeoutNetworkError
17
23
 
@@ -321,6 +327,7 @@ class NiquestsTransport:
321
327
  rate: float = 10,
322
328
  capacity: float = 50,
323
329
  connect_retries: int = 2,
330
+ timeout: TimeoutType = (10, 60),
324
331
  proxies: ProxyType | None = None,
325
332
  cert: TLSClientCertType | None = None,
326
333
  verify: TLSVerifyType | None = None,
@@ -350,6 +357,7 @@ class NiquestsTransport:
350
357
  self.cert = cert
351
358
  self.verify = verify
352
359
  self.hooks = hooks
360
+ self.timeout = timeout
353
361
  self._max_concurrency = max_concurrency
354
362
  self._capacity = _CapacityLimiter(max_concurrency)
355
363
  self._closed = False
@@ -406,10 +414,12 @@ class NiquestsTransport:
406
414
  try:
407
415
  for position, request in enumerate(chunk):
408
416
  try:
417
+ kwargs = dict(request.kwargs)
418
+ kwargs.setdefault("timeout", self.timeout)
409
419
  response = await self._client.request(
410
420
  request.method,
411
421
  request.url,
412
- **dict(request.kwargs),
422
+ **kwargs,
413
423
  proxies=self.proxies,
414
424
  hooks=self.hooks,
415
425
  cert=self.cert,
@@ -480,10 +490,12 @@ class NiquestsTransport:
480
490
  response: Response | None = None
481
491
  try:
482
492
  try:
493
+ stream_kwargs = dict(request.kwargs)
494
+ stream_kwargs.setdefault("timeout", self.timeout)
483
495
  response = await self._client.request(
484
496
  request.method,
485
497
  request.url,
486
- **dict(request.kwargs),
498
+ **stream_kwargs,
487
499
  stream=True,
488
500
  proxies=self.proxies,
489
501
  hooks=self.hooks,
@@ -118,6 +118,10 @@ class Credential(BaseModel):
118
118
  current_time = int(time.time())
119
119
  return current_time >= self.musickey_create_time + self.key_expires_in
120
120
 
121
+ def is_valid(self) -> bool:
122
+ """检查凭据是否包含可用登录态 (musicid 与 musickey 均有效)."""
123
+ return self.musicid > 0 and bool(self.musickey)
124
+
121
125
 
122
126
  class RequestItem(TypedDict):
123
127
  """请求项."""
@@ -44,7 +44,7 @@ class UserApi(ApiModule):
44
44
  if credential is not None:
45
45
  return credential
46
46
  current = self._executor.credential
47
- if current.musicid and current.musickey:
47
+ if current.is_valid():
48
48
  return current
49
49
  return self.PLACEHOLDER_CREDENTIAL
50
50
 
File without changes
@@ -8,6 +8,7 @@ from time import perf_counter
8
8
  from typing import Any
9
9
 
10
10
  from fastapi import FastAPI, HTTPException, Request
11
+ from fastapi.encoders import jsonable_encoder
11
12
  from fastapi.exceptions import RequestValidationError
12
13
  from fastapi.middleware.cors import CORSMiddleware
13
14
  from fastapi.responses import HTMLResponse, JSONResponse
@@ -241,6 +242,7 @@ def create_app() -> FastAPI:
241
242
  return error_response(
242
243
  status_code=422,
243
244
  msg="请求参数校验失败",
245
+ data={"errors": jsonable_encoder(exc.errors())},
244
246
  )
245
247
 
246
248
  @app.get("/", include_in_schema=False)
@@ -9,7 +9,6 @@ from qqmusic_api import Credential, Platform
9
9
  from qqmusic_api.core.engine import RequestEngine
10
10
 
11
11
  from .credential_pool import CallerCredential, ResolvedCredential
12
- from .credential_store import credential_has_login
13
12
  from .deps import get_credential_config, get_credential_pool
14
13
 
15
14
  logger = logging.getLogger(__name__)
@@ -34,10 +33,9 @@ async def configured_credential_for_api(
34
33
  Returns:
35
34
  调用方 Cookie 来源的凭证, 或共享凭证池来源的凭证; 只有后者允许写回共享池.
36
35
  """
37
- if credential_has_login(cookie_credential):
36
+ if cookie_credential.is_valid():
38
37
  logger.debug("API %s 使用 Cookie 凭证 (musicid: %s)", api_key, cookie_credential.musicid)
39
38
  return CallerCredential(credential=cookie_credential)
40
-
41
39
  credential_config = get_credential_config(request)
42
40
  if credential_config is None or not credential_config.api_enabled(api_key):
43
41
  logger.debug("API %s 未启用全局默认凭证或配置不存在", api_key)
@@ -149,7 +149,7 @@ class AccountConfig(BaseModel):
149
149
  merged.update({key: value for key, value in data.items() if key not in {"credential", "credential_json"}})
150
150
  return merged
151
151
 
152
- def has_login(self) -> bool:
152
+ def is_valid(self) -> bool:
153
153
  """判断是否包含可用登录凭证."""
154
154
  return self.musicid > 0 and bool(self.musickey)
155
155
 
@@ -19,7 +19,7 @@ from qqmusic_api.core.engine import RequestEngine, RequestScope, ScopedRequestEx
19
19
  from qqmusic_api.modules.login import LoginApi
20
20
 
21
21
  from .config import AccountConfig
22
- from .credential_store import CredentialStore, credential_has_login, credential_needs_refresh
22
+ from .credential_store import CredentialStore, credential_needs_refresh
23
23
 
24
24
  logger = logging.getLogger(__name__)
25
25
 
@@ -192,7 +192,7 @@ class CredentialPool:
192
192
  async def _check_one(musicid: int) -> None:
193
193
  async with semaphore:
194
194
  credential = await run_sync(self._store.get, musicid)
195
- if credential is None or not credential_has_login(credential):
195
+ if credential is None or not credential.is_valid():
196
196
  logger.warning("启动检查: 凭证 %s 不可用, 标记为无效", musicid)
197
197
  await run_sync(self._store.mark_invalid_row, musicid)
198
198
  return
@@ -58,7 +58,7 @@ class CredentialStore:
58
58
  """同步账号种子到状态库."""
59
59
  with self._lock:
60
60
  connection = self._connect()
61
- valid_accounts = [account for account in accounts if account.has_login()]
61
+ valid_accounts = [account for account in accounts if account.is_valid()]
62
62
  toml_ids = {account.musicid for account in valid_accounts}
63
63
 
64
64
  logger.info("同步账号种子: 总计 %d 个有效账号", len(valid_accounts))
@@ -93,7 +93,7 @@ class CredentialStore:
93
93
  credentials: list[Credential] = []
94
94
  for json_str in json_strings:
95
95
  credential = _load_credential(json_str)
96
- if credential is not None and credential_has_login(credential):
96
+ if credential is not None and credential.is_valid():
97
97
  credentials.append(credential)
98
98
  return credentials
99
99
 
@@ -112,7 +112,7 @@ class CredentialStore:
112
112
  logger.debug("凭证不存在: musicid %s", musicid)
113
113
  return None
114
114
  credential = _load_credential(row[0])
115
- if credential is None or not credential_has_login(credential):
115
+ if credential is None or not credential.is_valid():
116
116
  logger.debug("凭证无效或缺少登录信息: musicid %s", musicid)
117
117
  return None
118
118
  logger.debug("凭证获取成功: musicid %s", musicid)
@@ -124,7 +124,7 @@ class CredentialStore:
124
124
  Note:
125
125
  该入口用于独立写入单行; ``sync_accounts`` 走单事务批量路径, 直接复用内部 ``_upsert``.
126
126
  """
127
- if not credential_has_login(credential):
127
+ if not credential.is_valid():
128
128
  raise ValueError("Credential 缺少 musicid 或 musickey")
129
129
  logger.debug("写入账号种子: musicid %s", credential.musicid)
130
130
  with self._lock:
@@ -138,7 +138,7 @@ class CredentialStore:
138
138
  Returns:
139
139
  是否命中已有行; 未命中时返回 False 且不产生任何写入.
140
140
  """
141
- if not credential_has_login(credential):
141
+ if not credential.is_valid():
142
142
  raise ValueError("Credential 缺少 musicid 或 musickey")
143
143
  with self._lock:
144
144
  connection = self._connect()
@@ -254,11 +254,6 @@ def credential_needs_refresh(credential: Credential) -> bool:
254
254
  return False
255
255
 
256
256
 
257
- def credential_has_login(credential: Credential) -> bool:
258
- """判断 Credential 是否包含可用登录凭证."""
259
- return credential.musicid > 0 and bool(credential.musickey)
260
-
261
-
262
257
  def _load_credential(value: str) -> Credential | None:
263
258
  try:
264
259
  return Credential.model_validate_json(value)
@@ -1,6 +1,6 @@
1
1
  """Web API 标准响应结构."""
2
2
 
3
- from typing import Generic, TypeVar
3
+ from typing import Any, Generic, TypeVar
4
4
 
5
5
  from fastapi.responses import JSONResponse
6
6
  from pydantic import BaseModel, Field
@@ -21,6 +21,7 @@ class ErrorResponse(BaseModel):
21
21
 
22
22
  code: int = Field(default=-1, description="状态码, 错误时为 -1.")
23
23
  msg: str = Field(description="错误说明.")
24
+ data: Any = Field(default=None, description="错误详情 (如参数校验失败明细), 无详情时为 null.")
24
25
 
25
26
 
26
27
  def success_response(data: T) -> ApiResponse[T]:
@@ -32,7 +33,12 @@ def error_response(
32
33
  *,
33
34
  status_code: int,
34
35
  msg: str,
36
+ data: Any = None,
35
37
  headers: dict[str, str] | None = None,
36
38
  ) -> JSONResponse:
37
39
  """构造标准错误响应."""
38
- return JSONResponse(status_code=status_code, content=ErrorResponse(msg=msg).model_dump(), headers=headers)
40
+ return JSONResponse(
41
+ status_code=status_code,
42
+ content=ErrorResponse(msg=msg, data=data).model_dump(exclude_none=True),
43
+ headers=headers,
44
+ )
@@ -8,7 +8,7 @@ from ..modules.login import (
8
8
  QRCodeStatusData,
9
9
  WebQRLoginType,
10
10
  )
11
- from ..routing.route_types import AuthPolicy, WebRoute
11
+ from ..routing.route_types import AuthPolicy, HttpMethod, WebRoute
12
12
  from ._helpers import P, Q, R
13
13
 
14
14
  ROUTES: tuple[WebRoute, ...] = (
@@ -48,6 +48,7 @@ ROUTES: tuple[WebRoute, ...] = (
48
48
  "phone_authcode",
49
49
  "/login/phone/authcode",
50
50
  PhoneAuthCodeData,
51
+ methods=(HttpMethod.POST,),
51
52
  params=(
52
53
  Q("phone", int | None, None, "明文手机号."),
53
54
  Q("encrypted_phone", str | None, None, "加密手机号."),
@@ -59,6 +60,7 @@ ROUTES: tuple[WebRoute, ...] = (
59
60
  "phone_authorize",
60
61
  "/login/phone/authorize",
61
62
  Credential,
63
+ methods=(HttpMethod.POST,),
62
64
  params=(
63
65
  Q("auth_code", str, description="短信验证码 (字符串, 保留前导零)."),
64
66
  Q("phone", int | None, None, "明文手机号."),
@@ -24,7 +24,6 @@ from ..core.cache import (
24
24
  )
25
25
  from ..core.coalesce import Coalescer, Flight
26
26
  from ..core.credential_pool import CredentialPool, PoolCredential, ResolvedCredential
27
- from ..core.credential_store import credential_has_login
28
27
  from ..core.deps import get_cache_config, get_coalescer, get_credential_pool
29
28
  from ..core.error_mapping import HTTP_ERROR_MESSAGES, api_exception_status_code, is_upstream_failure
30
29
  from ..core.response import ApiResponse, error_response, success_response
@@ -235,7 +234,7 @@ async def _resolve_credential(context: RouteContext, *, strict: bool = True) ->
235
234
  cookie_credential,
236
235
  platform=context.platform,
237
236
  )
238
- if not credential_has_login(resolved.credential):
237
+ if not resolved.credential.is_valid():
239
238
  if strict:
240
239
  logger.error("凭证解析失败: 无有效登录凭证")
241
240
  raise HTTPException(status_code=401, detail="未提供有效的登录凭证")