qqmusic-api-python 0.6.7__tar.gz → 0.6.9__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.
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.dockerignore +0 -2
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.gitignore +1 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/AGENTS.md +21 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/PKG-INFO +6 -1
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/README.md +3 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/coding.md +6 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/release-notes.md +47 -1
- qqmusic_api_python-0.6.9/examples/upload_file.py +33 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/pyproject.toml +9 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/__init__.py +1 -1
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/client.py +27 -8
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/exceptions.py +8 -0
- qqmusic_api_python-0.6.9/qqmusic_api/models/album.py +121 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/base.py +5 -9
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/comment.py +56 -56
- qqmusic_api_python-0.6.9/qqmusic_api/models/helper.py +177 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/login.py +14 -2
- qqmusic_api_python-0.6.9/qqmusic_api/models/lyric.py +34 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/mv.py +35 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/private_message.py +32 -30
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/recommend.py +14 -14
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/search.py +13 -13
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/singer.py +51 -51
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/song.py +49 -49
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/songlist.py +4 -4
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/top.py +29 -27
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/user.py +133 -93
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/__init__.py +2 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/_base.py +15 -0
- qqmusic_api_python-0.6.9/qqmusic_api/modules/album.py +117 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/comment.py +2 -2
- qqmusic_api_python-0.6.9/qqmusic_api/modules/helper.py +84 -0
- qqmusic_api_python-0.6.9/qqmusic_api/modules/helper_utils.py +280 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/login.py +15 -2
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/mv.py +30 -1
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/private_message.py +30 -30
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/recommend.py +7 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/song.py +2 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/songlist.py +48 -8
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/user.py +174 -14
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/utils/device.py +2 -0
- qqmusic_api_python-0.6.9/tests/test_album.py +59 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_lyric.py +1 -7
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_mv.py +17 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_recommend.py +10 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_songlist.py +19 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_user.py +25 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/uv.lock +112 -0
- qqmusic_api_python-0.6.9/web/Dockerfile +41 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/README.md +30 -2
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/config.example.toml +5 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/requirements.txt +151 -198
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/run.py +0 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/app.py +5 -5
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/auth.py +52 -42
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/cache.py +25 -12
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/config.py +18 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/credential_store.py +20 -25
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/response.py +1 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/security.py +26 -20
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/songlist.py +10 -11
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/search.py +3 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/songlist.py +2 -0
- qqmusic_api_python-0.6.9/web/src/routes/user.py +186 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/docstrings.py +1 -3
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/executor.py +42 -20
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/router_factory.py +10 -2
- qqmusic_api_python-0.6.9/web/tests/conftest.py +12 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/tests/test_web_routes.py +25 -28
- qqmusic_api_python-0.6.7/qqmusic_api/models/album.py +0 -72
- qqmusic_api_python-0.6.7/qqmusic_api/models/lyric.py +0 -41
- qqmusic_api_python-0.6.7/qqmusic_api/modules/album.py +0 -58
- qqmusic_api_python-0.6.7/tests/test_album.py +0 -29
- qqmusic_api_python-0.6.7/web/Dockerfile +0 -23
- qqmusic_api_python-0.6.7/web/src/routes/user.py +0 -109
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.agents/skills/pydantic/SKILL.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.agents/skills/python-standards/SKILL.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.agents/skills/tarsio/SKILL.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.agents/skills/tarsio/references/api-reference.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.agents/skills/uv-package-manager/SKILL.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/renovate.json +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/workflows/checking.yaml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/workflows/docs.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/workflows/release.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.github/workflows/testing.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/.markdownlint-cli2.yaml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/CLAUDE.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/LICENSE +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/assets/qq-music.svg +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/cliff.toml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/contributing.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/index.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/core/client.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/core/exception.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/core/pagination.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/core/request.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/core/versioning.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/album.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/base.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/comment.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/login.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/lyric.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/mv.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/recommend.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/request.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/search.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/singer.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/song.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/songlist.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/top.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/model/user.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/album.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/comment.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/login.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/login_utils.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/lyric.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/mv.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/private_message.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/recommend.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/search.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/singer.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/song.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/songlist.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/top.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/reference/modules/user.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/client.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/credential.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/download.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/error-handling.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/login.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/pagination.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/start.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/docs/tutorial/web.md +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/examples/download_song.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/examples/get_all_sheets.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/examples/phone_login.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/examples/private_message.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/examples/qrcode_login.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/prek.toml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/algorithms/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/algorithms/sign.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/algorithms/tripledes.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/pagination.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/request.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/core/versioning.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/_validator.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/models/request.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/login_utils.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/lyric.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/search.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/singer.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/modules/top.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/utils/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/utils/common.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/utils/mqtt.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/qqmusic_api/utils/qimei.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/scripts/ag-1.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/conftest.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_comment.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_login.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_login_utils.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_private_message.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_search.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_singer.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_song.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/tests/test_top.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/.gitignore +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/accounts.example.toml +0 -0
- /qqmusic_api_python-0.6.7/web/docker-compose.yml → /qqmusic_api_python-0.6.9/web/docker-compose.example.yml +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/core/deps.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/comment.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/login.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/mv.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/singer.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/modules/song.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/_helpers.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/album.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/comment.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/login.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/lyric.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/mv.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/recommend.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/singer.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/song.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routes/top.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/__init__.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/params.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/src/routing/route_types.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/tests/test_web_core.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/tests/test_web_docstrings.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/tests/test_web_enums.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/web/tests/test_web_route_validation.py +0 -0
- {qqmusic_api_python-0.6.7 → qqmusic_api_python-0.6.9}/zensical.toml +0 -0
|
@@ -47,6 +47,27 @@
|
|
|
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
73
|
* **核心规约**:遵循 `docs/contributing.md` 中的详细规约。**在执行任务前,必须完整阅读该指南以确保合规。**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qqmusic-api-python
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.9
|
|
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
|
---
|
|
@@ -221,21 +221,24 @@ class Singer(Response):
|
|
|
221
221
|
|
|
222
222
|
### 需登录的接口
|
|
223
223
|
|
|
224
|
-
|
|
224
|
+
需要登录的接口通过 `_build_request` 的 `require_login` 参数校验凭证:
|
|
225
225
|
|
|
226
226
|
```python
|
|
227
227
|
def get_vip_info(self, *, credential: Credential | None = None):
|
|
228
228
|
"""获取 VIP 信息."""
|
|
229
|
-
target_credential = self._require_login(credential)
|
|
230
229
|
return self._build_request(
|
|
231
230
|
module="VipLogin.VipLoginInter",
|
|
232
231
|
method="vip_login_base",
|
|
233
232
|
param={},
|
|
234
|
-
credential=
|
|
233
|
+
credential=credential,
|
|
235
234
|
response_model=UserVipInfoResponse,
|
|
235
|
+
require_login=True,
|
|
236
236
|
)
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
+
> 若接口需要凭证对象的字段来构建请求参数,
|
|
240
|
+
> 仍可显式调用 `_require_login` 获取凭证对象。
|
|
241
|
+
|
|
239
242
|
## 翻页与换一批
|
|
240
243
|
|
|
241
244
|
### 连续翻页
|
|
@@ -1,18 +1,64 @@
|
|
|
1
1
|
|
|
2
|
-
##
|
|
2
|
+
## [[0.6.8](https://github.com/L-1124/QQMusicApi/compare/v0.6.7..v0.6.8)] - 2026-07-01
|
|
3
|
+
|
|
4
|
+
### Bug 修复
|
|
5
|
+
|
|
6
|
+
* **(web)** 禁用 FastAPI 默认按别名响应,使 JSON 输出与 Python 原生变量名保持一致 ([32459a5](https://github.com/L-1124/QQMusicApi/commit/32459a54c03d8a0a738f1917f9eb19fc6f9ac4ef)) by [@L-1124](https://github.com/L-1124)
|
|
7
|
+
|
|
8
|
+
### 功能更新
|
|
9
|
+
|
|
10
|
+
* **(core)** 新增 SignatureRequiredError 错误码 2000 处理 ([a73313a](https://github.com/L-1124/QQMusicApi/commit/a73313a91549a156358ad9311d0e20d7401b861b)) by [@L-1124](https://github.com/L-1124)
|
|
11
|
+
* **(core)** _ensure_session 添加 24h 保活机制 ([2290a32](https://github.com/L-1124/QQMusicApi/commit/2290a32304bcd9052365f60c67f2d4f6b00e4d7e)) by [@L-1124](https://github.com/L-1124)
|
|
12
|
+
* **(helper)** 新增辅助功能接口 ([eb0c40c](https://github.com/L-1124/QQMusicApi/commit/eb0c40c1461826955a1eb005afb723438730142a)) by [@L-1124](https://github.com/L-1124)
|
|
13
|
+
* **(login)** 支持登出API ([73f2a7e](https://github.com/L-1124/QQMusicApi/commit/73f2a7ee9ad1d48cbec2d6aa9dbf844f44b573c2)) by [@L-1124](https://github.com/L-1124)
|
|
14
|
+
* **(lyric)** [**breaking**] 彻底移除 crypt 字段,隐式处理加密状态 ([80edc40](https://github.com/L-1124/QQMusicApi/commit/80edc40e41331f6b5c11146d5daf6eccf344181f)) by [@L-1124](https://github.com/L-1124)
|
|
15
|
+
* **(lyric)** [**breaking**] 移除 decrypt 方法,改为默认解密 ([24949c4](https://github.com/L-1124/QQMusicApi/commit/24949c4df8c63b02b35dd69c30e2a8f40d234dfb)) by [@L-1124](https://github.com/L-1124)
|
|
16
|
+
* **(song)** 添加特殊歌曲文件类型 TRY_OGG_640 ([fef7e8c](https://github.com/L-1124/QQMusicApi/commit/fef7e8ceb220aa477ea7d8498f8ebfd240f72cc6)) by [@L-1124](https://github.com/L-1124)
|
|
17
|
+
* **(user)** 新增收藏/取消收藏歌单 API ([7865434](https://github.com/L-1124/QQMusicApi/commit/7865434782dd205815222fe716f52bac9f84aeec)) by [@jinzhongjia](https://github.com/jinzhongjia) in [#281](https://github.com/L-1124/QQMusicApi/pull/281)
|
|
18
|
+
* **(user)** 新增 FeedbackBlack 黑名单 API ([4340554](https://github.com/L-1124/QQMusicApi/commit/4340554aaaafaef175eead7ebced596538bc65e2)) by [@L-1124](https://github.com/L-1124)
|
|
19
|
+
* **(web)** 启用 FastAPI 内置 Swagger UI 和 ReDoc,更新文档地址说明 ([a3245ad](https://github.com/L-1124/QQMusicApi/commit/a3245ad3d3863c7f7eec94352d169a32ba4478c6)) by [@L-1124](https://github.com/L-1124)
|
|
20
|
+
* **(web)** 重构 Dockerfile 为多阶段构建,修复非 root 用户 uv 缓存权限问题 ([00e16a3](https://github.com/L-1124/QQMusicApi/commit/00e16a37b62e989de37232e8af7e77167a28e823)) by [@L-1124](https://github.com/L-1124)
|
|
21
|
+
|
|
22
|
+
### 功能重构
|
|
23
|
+
|
|
24
|
+
* **(core)** 移除 _session_cache 冗余缓存,简化会话验证逻辑 ([0b12b9d](https://github.com/L-1124/QQMusicApi/commit/0b12b9d041a8be24ad84d60bd2ceaed76b81fe92)) by [@L-1124](https://github.com/L-1124)
|
|
25
|
+
* **(models)** [**breaking**] 将所有模型中的 alias 统一替换为 validation_alias,隔离序列化字段名 ([c611b91](https://github.com/L-1124/QQMusicApi/commit/c611b91d607d36327662a80d0e126a6958b21bd5)) by [@L-1124](https://github.com/L-1124)
|
|
26
|
+
* **(modules)** 移除冗余的 _require_login 调用,统一使用 require_login 参数 ([1a666f4](https://github.com/L-1124/QQMusicApi/commit/1a666f45ae968c235066c07e8b3e82096c3fc668)) by [@L-1124](https://github.com/L-1124)
|
|
27
|
+
* **(modules)** 将 _require_login 收敛到 _build_request 的 require_login 参数中 ([d1a92ca](https://github.com/L-1124/QQMusicApi/commit/d1a92ca07d5a98f3f443453e5fc77b8f8c8dc44e)) by [@L-1124](https://github.com/L-1124)
|
|
28
|
+
|
|
29
|
+
### 文档更新
|
|
30
|
+
|
|
31
|
+
* **(coding)** 更新需登录接口的编码规范,使用 require_login 参数替代 _require_login ([9e56215](https://github.com/L-1124/QQMusicApi/commit/9e562152ec8039b3045ae6c51006401c93b36a36)) by [@L-1124](https://github.com/L-1124)
|
|
32
|
+
* **(dislike)** 更新不喜欢列表项和响应数据的文档说明 ([5dbf711](https://github.com/L-1124/QQMusicApi/commit/5dbf711e46a69f99940f048504446b9e074fd21f)) by [@L-1124](https://github.com/L-1124)
|
|
33
|
+
* **(login)** 更新二维码和手机验证码登录状态的文档注释 ([f31d4d0](https://github.com/L-1124/QQMusicApi/commit/f31d4d0132cb61a9935ebea92657fcfa6591926c)) by [@L-1124](https://github.com/L-1124)
|
|
34
|
+
* **(readme)** 添加 DeepWiki 相关链接 ([fcea758](https://github.com/L-1124/QQMusicApi/commit/fcea758b80a824cb513a8bdfc8b247da786f5a1e)) by [@L-1124](https://github.com/L-1124)
|
|
35
|
+
|
|
36
|
+
### 贡献者
|
|
37
|
+
|
|
38
|
+
* @L-1124
|
|
39
|
+
* @jinzhongjia [#281](https://github.com/L-1124/QQMusicApi/pull/281)
|
|
40
|
+
* @github-actions[bot]
|
|
41
|
+
|
|
42
|
+
## [[0.6.7](https://github.com/L-1124/QQMusicApi/compare/v0.6.6..v0.6.7)] - 2026-06-17
|
|
3
43
|
|
|
4
44
|
### 功能更新
|
|
5
45
|
|
|
46
|
+
* **(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)
|
|
47
|
+
* **(qimei)** 增加 24 小时过期重新获取逻辑 ([05aed29](https://github.com/L-1124/QQMusicApi/commit/05aed29096dff31b7d0cbb26ccc66ec50da38bdc)) by [@L-1124](https://github.com/L-1124)
|
|
6
48
|
* **(web)** 添加 has_sheet 路由 ([9e7a143](https://github.com/L-1124/QQMusicApi/commit/9e7a1439ff597ae43a4ef99d88ec08ee32889b9a)) by [@L-1124](https://github.com/L-1124)
|
|
7
49
|
|
|
8
50
|
### 文档更新
|
|
9
51
|
|
|
52
|
+
* **(coding)** 重写 API 编写指南,补充开发细节 ([9db46de](https://github.com/L-1124/QQMusicApi/commit/9db46def73ec6c2d9826c4a15bc2eb7ba9ed0f37)) by [@L-1124](https://github.com/L-1124)
|
|
53
|
+
* 为固定请求平台的 API 补充 docstring 说明 ([aba712e](https://github.com/L-1124/QQMusicApi/commit/aba712e56a7485b4184941480c05f370cd53c548)) by [@L-1124](https://github.com/L-1124)
|
|
10
54
|
* 完善快速开始文档并新增多篇核心教程 ([d6143cd](https://github.com/L-1124/QQMusicApi/commit/d6143cdc047ebeb4963b061680a21103ba3d58d4)) by [@L-1124](https://github.com/L-1124)
|
|
11
55
|
|
|
12
56
|
### 贡献者
|
|
13
57
|
|
|
14
58
|
* @L-1124
|
|
59
|
+
* @jinzhongjia [#269](https://github.com/L-1124/QQMusicApi/pull/269)
|
|
15
60
|
* @github-actions[bot]
|
|
61
|
+
* @renovate[bot]
|
|
16
62
|
|
|
17
63
|
## [[0.6.6](https://github.com/L-1124/QQMusicApi/compare/v0.6.5..v0.6.6)] - 2026-06-13
|
|
18
64
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""辅助功能文件上传示例."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from qqmusic_api import Client
|
|
6
|
+
from qqmusic_api.modules.helper_utils import UploadFileSession
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
async def main() -> None:
|
|
10
|
+
"""文件上传示例."""
|
|
11
|
+
file_to_upload = ""
|
|
12
|
+
|
|
13
|
+
async with Client() as client:
|
|
14
|
+
session = UploadFileSession(
|
|
15
|
+
api=client.helper,
|
|
16
|
+
bus_id="songlist", # 歌单封面
|
|
17
|
+
max_concurrency=3,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
object_infos = await session.upload([file_to_upload])
|
|
21
|
+
print(f"总计成功上传 {len(object_infos)} 个文件!")
|
|
22
|
+
for info in object_infos:
|
|
23
|
+
print(f"存储桶: {info.storage.bucket.name}")
|
|
24
|
+
print(f"区域: {info.storage.bucket.region}")
|
|
25
|
+
print(f"对象键: {info.storage.object_key}")
|
|
26
|
+
print(f"CDN 地址: {info.url.cdn_url}")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
try:
|
|
31
|
+
asyncio.run(main())
|
|
32
|
+
except KeyboardInterrupt:
|
|
33
|
+
print("\n用户取消操作")
|
|
@@ -49,6 +49,11 @@ documentation = "https://l-1124.github.io/QQMusicApi/"
|
|
|
49
49
|
homepage = "https://l-1124.github.io/QQMusicApi/"
|
|
50
50
|
repository = "https://github.com/l-1124/QQMusicApi"
|
|
51
51
|
|
|
52
|
+
[project.optional-dependencies]
|
|
53
|
+
upload = [
|
|
54
|
+
"cos-python-sdk-v5>=1.9.44",
|
|
55
|
+
]
|
|
56
|
+
|
|
52
57
|
[dependency-groups]
|
|
53
58
|
dev = [
|
|
54
59
|
"tarsio[cli]>=0.5.1",
|
|
@@ -56,6 +61,7 @@ dev = [
|
|
|
56
61
|
{ include-group = "docs" },
|
|
57
62
|
{ include-group = "linting" },
|
|
58
63
|
{ include-group = "testing" },
|
|
64
|
+
{ include-group = "helper" },
|
|
59
65
|
]
|
|
60
66
|
docs = [
|
|
61
67
|
"docstring-inheritance>=3.0.0",
|
|
@@ -65,6 +71,9 @@ docs = [
|
|
|
65
71
|
"mkdocstrings-python>=2.0.3",
|
|
66
72
|
"zensical>=0.0.30",
|
|
67
73
|
]
|
|
74
|
+
helper = [
|
|
75
|
+
"cos-python-sdk-v5>=1.9.44",
|
|
76
|
+
]
|
|
68
77
|
linting = [
|
|
69
78
|
"prek>=0.3.5",
|
|
70
79
|
"pyrefly>=0.56.0",
|
|
@@ -17,7 +17,7 @@ from urllib3.util.retry import Retry
|
|
|
17
17
|
from ..algorithms import zzc_sign
|
|
18
18
|
from ..models.request import Credential, JceRequest, JceRequestItem, JceResponse, JceResponseItem, RequestItem
|
|
19
19
|
from ..utils.common import bool_to_int
|
|
20
|
-
from ..utils.device import DeviceManager
|
|
20
|
+
from ..utils.device import Device, DeviceManager
|
|
21
21
|
from ..utils.qimei import QimeiManager
|
|
22
22
|
from .exceptions import (
|
|
23
23
|
ApiDataError,
|
|
@@ -27,6 +27,7 @@ from .exceptions import (
|
|
|
27
27
|
HTTPError,
|
|
28
28
|
NetworkError,
|
|
29
29
|
RatelimitedError,
|
|
30
|
+
SignatureRequiredError,
|
|
30
31
|
)
|
|
31
32
|
from .request import Request, RequestResultT, _build_result
|
|
32
33
|
from .versioning import DEFAULT_VERSION_POLICY, Platform, VersionPolicy
|
|
@@ -34,6 +35,7 @@ from .versioning import DEFAULT_VERSION_POLICY, Platform, VersionPolicy
|
|
|
34
35
|
if TYPE_CHECKING:
|
|
35
36
|
from ..modules.album import AlbumApi
|
|
36
37
|
from ..modules.comment import CommentApi
|
|
38
|
+
from ..modules.helper import HelperApi
|
|
37
39
|
from ..modules.login import LoginApi
|
|
38
40
|
from ..modules.lyric import LyricApi
|
|
39
41
|
from ..modules.mv import MvApi
|
|
@@ -107,7 +109,6 @@ class Client:
|
|
|
107
109
|
|
|
108
110
|
self._version_policy: VersionPolicy = DEFAULT_VERSION_POLICY
|
|
109
111
|
self._session_lock = anyio.Lock()
|
|
110
|
-
self._session_initialized = False
|
|
111
112
|
self._qimei_manager = QimeiManager(
|
|
112
113
|
device_store=self._device_store,
|
|
113
114
|
app_version=self._version_policy.get_qimei_app_version(),
|
|
@@ -116,12 +117,22 @@ class Client:
|
|
|
116
117
|
)
|
|
117
118
|
|
|
118
119
|
async def _ensure_session(self) -> None:
|
|
120
|
+
"""获取 `Platform.ANDROID` 会话信息."""
|
|
121
|
+
|
|
122
|
+
def _is_session_valid(dev: "Device") -> bool:
|
|
123
|
+
return (
|
|
124
|
+
dev.session_save_time is not None
|
|
125
|
+
and (int(time.time()) - dev.session_save_time) < 86400
|
|
126
|
+
and bool(dev.session_uid and dev.session_sid)
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
device = await self._device_store.get_device()
|
|
130
|
+
if _is_session_valid(device):
|
|
131
|
+
return
|
|
132
|
+
|
|
119
133
|
async with self._session_lock:
|
|
120
|
-
if self._session_initialized:
|
|
121
|
-
return
|
|
122
134
|
device = await self._device_store.get_device()
|
|
123
|
-
if device
|
|
124
|
-
self._session_initialized = True
|
|
135
|
+
if _is_session_valid(device):
|
|
125
136
|
return
|
|
126
137
|
|
|
127
138
|
finalcomm = self._version_policy.build_comm(
|
|
@@ -168,8 +179,15 @@ class Client:
|
|
|
168
179
|
device.session_uid = str(session_data["uid"])
|
|
169
180
|
device.session_sid = session_data["sid"]
|
|
170
181
|
device.session_vkey = session_data.get("vkey")
|
|
182
|
+
device.session_save_time = int(time.time())
|
|
171
183
|
await self._device_store.save_device()
|
|
172
|
-
|
|
184
|
+
|
|
185
|
+
@cached_property
|
|
186
|
+
def helper(self) -> "HelperApi":
|
|
187
|
+
"""辅助模块."""
|
|
188
|
+
from ..modules.helper import HelperApi
|
|
189
|
+
|
|
190
|
+
return HelperApi(self)
|
|
173
191
|
|
|
174
192
|
@cached_property
|
|
175
193
|
def comment(self) -> "CommentApi":
|
|
@@ -604,8 +622,9 @@ class Client:
|
|
|
604
622
|
"RequestResultT",
|
|
605
623
|
{"code": code, "data": data} if request.is_jce else item,
|
|
606
624
|
)
|
|
607
|
-
|
|
608
625
|
match code:
|
|
626
|
+
case 2000:
|
|
627
|
+
raise SignatureRequiredError(code=code, data=data)
|
|
609
628
|
case 2001:
|
|
610
629
|
raise RatelimitedError(code=code, data=data)
|
|
611
630
|
case 1000 | 104401 | 104400:
|
|
@@ -19,6 +19,7 @@ __all__ = [
|
|
|
19
19
|
"LoginRateLimitError",
|
|
20
20
|
"NetworkError",
|
|
21
21
|
"RatelimitedError",
|
|
22
|
+
"SignatureRequiredError",
|
|
22
23
|
]
|
|
23
24
|
|
|
24
25
|
|
|
@@ -202,3 +203,10 @@ class LoginRateLimitError(LoginError):
|
|
|
202
203
|
data: Any = None,
|
|
203
204
|
):
|
|
204
205
|
super().__init__(message, code=code, data=data)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class SignatureRequiredError(CgiApiException):
|
|
209
|
+
"""请求需要签名 (code=2000)."""
|
|
210
|
+
|
|
211
|
+
def __init__(self, *, code: int = 2000, data: Any = None) -> None:
|
|
212
|
+
super().__init__("请求需要签名", code=code, data=data)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Album API 返回模型定义."""
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from .base import Album, Singer, Song
|
|
6
|
+
from .request import Response
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class AlbumDetail(Album):
|
|
10
|
+
"""专辑详情页返回的核心专辑信息.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
subtitle: 专辑副标题.
|
|
14
|
+
time_public: 发行日期.
|
|
15
|
+
desc: 专辑简介.
|
|
16
|
+
language: 专辑语种.
|
|
17
|
+
album_type: 专辑类型描述.
|
|
18
|
+
genre: 专辑流派文本.
|
|
19
|
+
wikiurl: 百科链接.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
subtitle: str = ""
|
|
23
|
+
time_public: str = Field(default="", validation_alias="publishDate")
|
|
24
|
+
desc: str = ""
|
|
25
|
+
language: str = ""
|
|
26
|
+
album_type: str = Field(default="", validation_alias="albumType")
|
|
27
|
+
genre: str = ""
|
|
28
|
+
wikiurl: str = ""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AlbumCompany(Response):
|
|
32
|
+
"""专辑详情接口中的发行公司信息.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
id: 公司 ID.
|
|
36
|
+
name: 公司名称.
|
|
37
|
+
is_show: 是否展示.
|
|
38
|
+
brief: 公司简介.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
id: int = Field(validation_alias="ID")
|
|
42
|
+
name: str
|
|
43
|
+
is_show: int = Field(validation_alias="isShow")
|
|
44
|
+
brief: str = ""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class GetAlbumDetailResponse(Response):
|
|
48
|
+
"""专辑详情接口聚合后的响应体.
|
|
49
|
+
|
|
50
|
+
Attributes:
|
|
51
|
+
album: 专辑基础信息与补充描述.
|
|
52
|
+
company: 发行公司信息.
|
|
53
|
+
singers: 专辑署名歌手列表.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
album: AlbumDetail = Field(validation_alias="basicInfo")
|
|
57
|
+
company: AlbumCompany
|
|
58
|
+
singers: list[Singer] = Field(default_factory=list, json_schema_extra={"jsonpath": "$.singer.singerList"})
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class GetAlbumSongResponse(Response):
|
|
62
|
+
"""专辑歌曲列表接口返回的分页结果.
|
|
63
|
+
|
|
64
|
+
Attributes:
|
|
65
|
+
album_mid: 专辑 MID.
|
|
66
|
+
total_num: 歌曲总数.
|
|
67
|
+
song_list: 当前响应携带的专辑歌曲列表.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
album_mid: str = Field(validation_alias="albumMid")
|
|
71
|
+
total_num: int = Field(validation_alias="totalNum")
|
|
72
|
+
song_list: list[Song] = Field(default_factory=list, json_schema_extra={"jsonpath": "$.songList[*].songInfo"})
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class NewAlbumItem(Album):
|
|
76
|
+
"""新碟上架列表中的单张专辑摘要.
|
|
77
|
+
|
|
78
|
+
Attributes:
|
|
79
|
+
singers: 专辑署名歌手列表.
|
|
80
|
+
release_time: 发行日期, 格式通常为 YYYY-MM-DD.
|
|
81
|
+
type: 专辑类型.
|
|
82
|
+
area: 地区标识.
|
|
83
|
+
genre: 流派标识.
|
|
84
|
+
language: 语种标识.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
singers: list[Singer] = Field(default_factory=list)
|
|
88
|
+
release_time: str = ""
|
|
89
|
+
type: int = 0
|
|
90
|
+
area: int = 0
|
|
91
|
+
genre: int = 0
|
|
92
|
+
language: int = 0
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class GetNewAlbumResponse(Response):
|
|
96
|
+
"""新碟上架接口的响应体.
|
|
97
|
+
|
|
98
|
+
Attributes:
|
|
99
|
+
total: 该地区下新碟总数.
|
|
100
|
+
albums: 当前页新碟列表.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
total: int = 0
|
|
104
|
+
albums: list[NewAlbumItem] = Field(default_factory=list)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class AlbumFavWriteResponse(Response):
|
|
108
|
+
"""收藏 / 取消收藏专辑的写操作响应.
|
|
109
|
+
|
|
110
|
+
Attributes:
|
|
111
|
+
result: 操作结果码, 0 表示成功.
|
|
112
|
+
failed_album_id: 操作失败的专辑 ID 列表, 全部成功时为空.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
result: int = 0
|
|
116
|
+
failed_album_id: list[int] = Field(default_factory=list, validation_alias="v_failedAlbumId")
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def success(self) -> bool:
|
|
120
|
+
"""是否操作成功 (result 为 0 且无失败项)."""
|
|
121
|
+
return self.result == 0 and not self.failed_album_id
|
|
@@ -18,21 +18,17 @@ _PHOTO_NEW_SIZE_SEGMENTS: Final[dict[int, str]] = {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
def _normalize_cover_size(size: CoverSize) -> str:
|
|
22
|
-
"""返回 `photo_new` 模板使用的尺寸片段."""
|
|
23
|
-
try:
|
|
24
|
-
return _PHOTO_NEW_SIZE_SEGMENTS[size]
|
|
25
|
-
except KeyError as exc:
|
|
26
|
-
raise ValueError("not supported size") from exc
|
|
27
|
-
|
|
28
|
-
|
|
29
21
|
def _build_photo_new_cover_url(kind: str, mid: str, size: CoverSize) -> str:
|
|
30
22
|
"""按 `photo_new` 规则拼接封面链接."""
|
|
31
23
|
normalized_mid = mid.strip()
|
|
32
24
|
if not normalized_mid:
|
|
33
25
|
return ""
|
|
34
26
|
|
|
35
|
-
|
|
27
|
+
try:
|
|
28
|
+
cover_size = _PHOTO_NEW_SIZE_SEGMENTS[size]
|
|
29
|
+
return f"https://y.gtimg.cn/music/photo_new/{kind}{cover_size}M000{normalized_mid}.jpg"
|
|
30
|
+
except KeyError as exc:
|
|
31
|
+
raise ValueError("not supported size") from exc
|
|
36
32
|
|
|
37
33
|
|
|
38
34
|
class Singer(Response):
|
|
@@ -85,29 +85,29 @@ class CommentItem(Response):
|
|
|
85
85
|
sub_comments: 子评论列表.
|
|
86
86
|
"""
|
|
87
87
|
|
|
88
|
-
cmid: str = Field(
|
|
89
|
-
seq_no: str = Field(
|
|
90
|
-
nick: str = Field(
|
|
91
|
-
avatar: str = Field(
|
|
92
|
-
encrypt_uin: str = Field(
|
|
93
|
-
content: str = Field(
|
|
94
|
-
pub_time: int = Field(
|
|
95
|
-
praise_num: int = Field(
|
|
96
|
-
reply_cnt: int = Field(
|
|
97
|
-
is_praised: int = Field(
|
|
98
|
-
is_self: int = Field(
|
|
99
|
-
state: int = Field(
|
|
100
|
-
hot_score: str = Field(
|
|
101
|
-
rec_score: str = Field(
|
|
102
|
-
song_id: int = Field(
|
|
103
|
-
song_name: str = Field(
|
|
104
|
-
singer_names: str = Field(
|
|
105
|
-
song_ts_elems: list[dict[str, Any]] = Field(default_factory=list,
|
|
106
|
-
hash_tag_list: list[dict[str, Any]] = Field(default_factory=list,
|
|
107
|
-
little_tails: list[dict[str, Any]] = Field(default_factory=list,
|
|
108
|
-
icon_list: list[dict[str, Any]] = Field(default_factory=list,
|
|
109
|
-
vip_ui: dict[str, Any] = Field(default_factory=dict,
|
|
110
|
-
sub_comments: list[dict[str, Any]] = Field(default_factory=list,
|
|
88
|
+
cmid: str = Field(validation_alias="CmId")
|
|
89
|
+
seq_no: str = Field(validation_alias="SeqNo")
|
|
90
|
+
nick: str = Field(validation_alias="Nick")
|
|
91
|
+
avatar: str = Field(validation_alias="Avatar")
|
|
92
|
+
encrypt_uin: str = Field(validation_alias="EncryptUin")
|
|
93
|
+
content: str = Field(validation_alias="Content")
|
|
94
|
+
pub_time: int = Field(validation_alias="PubTime")
|
|
95
|
+
praise_num: int = Field(validation_alias="PraiseNum")
|
|
96
|
+
reply_cnt: int = Field(validation_alias="ReplyCnt")
|
|
97
|
+
is_praised: int = Field(validation_alias="IsPraised")
|
|
98
|
+
is_self: int = Field(validation_alias="IsSelf")
|
|
99
|
+
state: int = Field(validation_alias="State")
|
|
100
|
+
hot_score: str = Field(validation_alias="HotScore")
|
|
101
|
+
rec_score: str = Field(validation_alias="RecScore")
|
|
102
|
+
song_id: int = Field(validation_alias="SongId")
|
|
103
|
+
song_name: str = Field(validation_alias="SongName")
|
|
104
|
+
singer_names: str = Field(validation_alias="SingerNames")
|
|
105
|
+
song_ts_elems: list[dict[str, Any]] = Field(default_factory=list, validation_alias="SongTsElems")
|
|
106
|
+
hash_tag_list: list[dict[str, Any]] = Field(default_factory=list, validation_alias="HashTagList")
|
|
107
|
+
little_tails: list[dict[str, Any]] = Field(default_factory=list, validation_alias="LittleTails")
|
|
108
|
+
icon_list: list[dict[str, Any]] = Field(default_factory=list, validation_alias="IconList")
|
|
109
|
+
vip_ui: dict[str, Any] = Field(default_factory=dict, validation_alias="VipUI")
|
|
110
|
+
sub_comments: list[dict[str, Any]] = Field(default_factory=list, validation_alias="SubComments")
|
|
111
111
|
|
|
112
112
|
|
|
113
113
|
class CommentListResponse(Response):
|
|
@@ -136,13 +136,13 @@ class CommentListResponse(Response):
|
|
|
136
136
|
has_more: int = Field(json_schema_extra={"jsonpath": "$.CommentList.HasMore"})
|
|
137
137
|
next_offset: int = Field(json_schema_extra={"jsonpath": "$.CommentList.NextOffset"})
|
|
138
138
|
total: int = Field(json_schema_extra={"jsonpath": "$.CommentList.Total"})
|
|
139
|
-
total_cm_num: int = Field(
|
|
140
|
-
comment_tip: str = Field(
|
|
141
|
-
comment_h5_page: str = Field(
|
|
142
|
-
has_ts_cm: int = Field(
|
|
143
|
-
share_cnt: int = Field(
|
|
144
|
-
msg: str = Field(
|
|
145
|
-
sub_code: int = Field(
|
|
139
|
+
total_cm_num: int = Field(validation_alias="TotalCmNum")
|
|
140
|
+
comment_tip: str = Field(validation_alias="CommentTip")
|
|
141
|
+
comment_h5_page: str = Field(validation_alias="CommentH5Page")
|
|
142
|
+
has_ts_cm: int = Field(validation_alias="HasTsCm")
|
|
143
|
+
share_cnt: int = Field(validation_alias="ShareCnt")
|
|
144
|
+
msg: str = Field(validation_alias="Msg")
|
|
145
|
+
sub_code: int = Field(validation_alias="SubCode")
|
|
146
146
|
|
|
147
147
|
|
|
148
148
|
class MomentCommentItem(Response):
|
|
@@ -167,22 +167,22 @@ class MomentCommentItem(Response):
|
|
|
167
167
|
little_tails: 尾巴挂件列表.
|
|
168
168
|
"""
|
|
169
169
|
|
|
170
|
-
cmid: str = Field(
|
|
171
|
-
seq_no: str = Field(
|
|
172
|
-
content: str = Field(
|
|
173
|
-
encrypt_uin: str = Field(
|
|
174
|
-
pub_time: int = Field(
|
|
175
|
-
praise_num: int = Field(
|
|
176
|
-
reply_cnt: int = Field(
|
|
177
|
-
state: int = Field(
|
|
178
|
-
is_self: int = Field(
|
|
179
|
-
location: str = Field(
|
|
180
|
-
phone_type: str = Field(
|
|
181
|
-
pic: str = Field(
|
|
182
|
-
pic_size: str = Field(
|
|
183
|
-
song_ts_elems: list[dict[str, Any]] = Field(default_factory=list,
|
|
184
|
-
hash_tag_list: list[dict[str, Any]] = Field(default_factory=list,
|
|
185
|
-
little_tails: list[dict[str, Any]] = Field(default_factory=list,
|
|
170
|
+
cmid: str = Field(validation_alias="CmId")
|
|
171
|
+
seq_no: str = Field(validation_alias="SeqNo")
|
|
172
|
+
content: str = Field(validation_alias="Content")
|
|
173
|
+
encrypt_uin: str = Field(validation_alias="EncryptUin")
|
|
174
|
+
pub_time: int = Field(validation_alias="PubTime")
|
|
175
|
+
praise_num: int = Field(validation_alias="PraiseNum")
|
|
176
|
+
reply_cnt: int = Field(validation_alias="ReplyCnt")
|
|
177
|
+
state: int = Field(validation_alias="State")
|
|
178
|
+
is_self: int = Field(validation_alias="IsSelf")
|
|
179
|
+
location: str = Field(validation_alias="Location")
|
|
180
|
+
phone_type: str = Field(validation_alias="PhoneType")
|
|
181
|
+
pic: str = Field(validation_alias="Pic")
|
|
182
|
+
pic_size: str = Field(validation_alias="PicSize")
|
|
183
|
+
song_ts_elems: list[dict[str, Any]] = Field(default_factory=list, validation_alias="SongTsElems")
|
|
184
|
+
hash_tag_list: list[dict[str, Any]] = Field(default_factory=list, validation_alias="HashTagList")
|
|
185
|
+
little_tails: list[dict[str, Any]] = Field(default_factory=list, validation_alias="LittleTails")
|
|
186
186
|
|
|
187
187
|
|
|
188
188
|
class MomentCommentResponse(Response):
|
|
@@ -198,11 +198,11 @@ class MomentCommentResponse(Response):
|
|
|
198
198
|
"""
|
|
199
199
|
|
|
200
200
|
comments: list[MomentCommentItem] = Field(default_factory=list, json_schema_extra={"jsonpath": "$.CmList[*]"})
|
|
201
|
-
has_more: int = Field(
|
|
202
|
-
next_pos: str = Field(default="",
|
|
203
|
-
hint: str = Field(
|
|
204
|
-
prev_list_loaded: int = Field(
|
|
205
|
-
map_cm_ext: dict[str, dict[str, Any]] = Field(default_factory=dict,
|
|
201
|
+
has_more: int = Field(validation_alias="HasMore")
|
|
202
|
+
next_pos: str = Field(default="", validation_alias="NextPos")
|
|
203
|
+
hint: str = Field(validation_alias="Hint")
|
|
204
|
+
prev_list_loaded: int = Field(validation_alias="PrevListLoaded")
|
|
205
|
+
map_cm_ext: dict[str, dict[str, Any]] = Field(default_factory=dict, validation_alias="MapCmExt")
|
|
206
206
|
|
|
207
207
|
|
|
208
208
|
class AddCommentResponse(Response):
|
|
@@ -217,9 +217,9 @@ class AddCommentResponse(Response):
|
|
|
217
217
|
verify_url: 验证码 URL (如果需要).
|
|
218
218
|
"""
|
|
219
219
|
|
|
220
|
-
subcode: int = Field(
|
|
221
|
-
msg: str = Field(
|
|
222
|
-
id: str = Field(
|
|
223
|
-
parent: str = Field(
|
|
220
|
+
subcode: int = Field(validation_alias="SubCode")
|
|
221
|
+
msg: str = Field(validation_alias="Msg")
|
|
222
|
+
id: str = Field(validation_alias="AddedCmId")
|
|
223
|
+
parent: str = Field(validation_alias="ParentCmId")
|
|
224
224
|
floor: int = Field(json_schema_extra={"jsonpath": "$.Floor.Num"})
|
|
225
|
-
verify_url: str = Field(
|
|
225
|
+
verify_url: str = Field(validation_alias="VerifyUrl")
|