qqmusic-api-python 0.6.0__tar.gz → 0.6.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.
- qqmusic_api_python-0.6.1/CLAUDE.md +1 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/PKG-INFO +1 -1
- qqmusic_api_python-0.6.1/docs/reference/modules/private_message.md +3 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/release-notes.md +25 -0
- qqmusic_api_python-0.6.1/examples/private_message.py +74 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/__init__.py +1 -1
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/client.py +9 -1
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/comment.py +20 -0
- qqmusic_api_python-0.6.1/qqmusic_api/models/private_message.py +350 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/__init__.py +2 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/comment.py +60 -1
- qqmusic_api_python-0.6.1/qqmusic_api/modules/private_message.py +518 -0
- qqmusic_api_python-0.6.1/tests/test_private_message.py +38 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/zensical.toml +1 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.agents/skills/pydantic/SKILL.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.agents/skills/python-standards/SKILL.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.agents/skills/tarsio/SKILL.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.agents/skills/tarsio/references/api-reference.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.agents/skills/uv-package-manager/SKILL.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.dockerignore +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/renovate.json +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/workflows/checking.yaml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/workflows/docs.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/workflows/release.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.github/workflows/testing.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.gitignore +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/.markdownlint-cli2.yaml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/AGENTS.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/LICENSE +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/README.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/assets/qq-music.svg +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/cliff.toml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/coding.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/contributing.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/index.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/core/client.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/core/exception.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/core/pagination.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/core/request.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/core/versioning.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/album.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/base.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/comment.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/login.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/lyric.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/mv.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/recommend.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/request.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/search.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/singer.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/song.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/songlist.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/top.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/model/user.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/album.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/comment.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/login.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/login_utils.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/lyric.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/mv.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/recommend.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/search.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/singer.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/song.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/songlist.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/top.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/reference/modules/user.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/tutorial/client.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/tutorial/credential.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/tutorial/pagination.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/tutorial/start.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/docs/tutorial/web.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/examples/download_song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/examples/phone_login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/examples/qrcode_login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/prek.toml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/pyproject.toml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/algorithms/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/algorithms/tripledes.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/exceptions.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/pagination.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/request.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/core/versioning.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/album.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/base.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/lyric.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/mv.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/recommend.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/request.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/search.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/singer.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/songlist.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/top.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/models/user.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/_base.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/album.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/login_utils.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/lyric.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/mv.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/recommend.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/search.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/singer.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/songlist.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/top.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/user.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/common.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/device.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/mqtt.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/qimei.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/scripts/ag-1.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/conftest.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_album.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_comment.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_login_utils.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_lyric.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_mv.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_recommend.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_search.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_singer.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_songlist.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_top.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/tests/test_user.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/uv.lock +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/.gitignore +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/Dockerfile +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/README.md +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/accounts.example.toml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/config.example.toml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/docker-compose.yml +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/run.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/app.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/auth.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/cache.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/config.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/credential_store.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/deps.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/response.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/core/security.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/mv.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/singer.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/modules/songlist.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/_helpers.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/album.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/comment.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/login.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/lyric.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/mv.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/recommend.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/search.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/singer.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/song.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/songlist.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/top.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routes/user.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/__init__.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/docstrings.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/executor.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/params.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/route_types.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/src/routing/router_factory.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/tests/test_web_docstrings.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/tests/test_web_enums.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/tests/test_web_route_validation.py +0 -0
- {qqmusic_api_python-0.6.0 → qqmusic_api_python-0.6.1}/web/tests/test_web_routes.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
|
|
2
|
+
## [[0.6.0](https://github.com/L-1124/QQMusicApi/compare/v0.5.3..v0.6.0)] - 2026-05-09
|
|
3
|
+
|
|
4
|
+
### Bug 修复
|
|
5
|
+
|
|
6
|
+
* **(login)** 修改手机验证码鉴权参数类型为字符串 ([5cfebc6](https://github.com/L-1124/QQMusicApi/commit/5cfebc67cc816e0ca1930f76386fc599215496af)) by [@L-1124](https://github.com/L-1124)
|
|
7
|
+
|
|
8
|
+
### 功能更新
|
|
9
|
+
|
|
10
|
+
* **(client)** 添加连接重试机制参数 ([38134a7](https://github.com/L-1124/QQMusicApi/commit/38134a74cfe9d3b623c46d74136687d9a2731848)) by [@L-1124](https://github.com/L-1124)
|
|
11
|
+
* **(core)** [**breaking**] 移除 `RequestGroup`,支持 `Client.gather` 批量并发请求,重构请求速率限制参数 ([632b6a8](https://github.com/L-1124/QQMusicApi/commit/632b6a85fe509bbbab7bbe6e7ae702e34ef49440)) by [@L-1124](https://github.com/L-1124)
|
|
12
|
+
* **(web)** 添加 Docker 支持 ([b6f4dfc](https://github.com/L-1124/QQMusicApi/commit/b6f4dfc824c45cdba784904fd937495ab15065cc)) by [@L-1124](https://github.com/L-1124)
|
|
13
|
+
* **(web)** 添加 Web 服务路由 ([154d714](https://github.com/L-1124/QQMusicApi/commit/154d714f4bd918ab6b23814f841b154e5b388c94)) by [@L-1124](https://github.com/L-1124) in [#247](https://github.com/L-1124/QQMusicApi/pull/247)
|
|
14
|
+
* [**breaking**] 不再支持配置 `Client` 部分参数并且修改并且初始化参数名 ([c4a7001](https://github.com/L-1124/QQMusicApi/commit/c4a7001a007128eba76b89004504b58be60c6f84)) by [@L-1124](https://github.com/L-1124)
|
|
15
|
+
|
|
16
|
+
### 功能重构
|
|
17
|
+
|
|
18
|
+
* **(algorithms)** [**breaking**] 移除 Web 端请求签名模块 ([21b3179](https://github.com/L-1124/QQMusicApi/commit/21b31794d89efebbf58505a4310dc95ecd9ba7f0)) by [@L-1124](https://github.com/L-1124)
|
|
19
|
+
* **(core)** 重构 API 客户端, 迁移 httpx → niquests ([fc4f1b7](https://github.com/L-1124/QQMusicApi/commit/fc4f1b77f2f001331f38a178a2a16e84279a4549)) by [@L-1124](https://github.com/L-1124)
|
|
20
|
+
* **(exception)** [**breaking**] 重构异常体系 ([3f7ef32](https://github.com/L-1124/QQMusicApi/commit/3f7ef3239f90cbcf3bf8ba64ab1561e89683df52)) by [@L-1124](https://github.com/L-1124)
|
|
21
|
+
|
|
22
|
+
### 贡献者
|
|
23
|
+
|
|
24
|
+
* @L-1124
|
|
25
|
+
* @github-actions[bot]
|
|
26
|
+
|
|
2
27
|
## [[0.5.3](https://github.com/L-1124/QQMusicApi/compare/v0.5.2..v0.5.3)] - 2026-05-01
|
|
3
28
|
|
|
4
29
|
### Bug 修复
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""私信只读接口示例."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
|
|
5
|
+
from qqmusic_api import Client, Credential
|
|
6
|
+
from qqmusic_api.models.private_message import PrivateMessageSession
|
|
7
|
+
|
|
8
|
+
MUSICID = 0
|
|
9
|
+
MUSICKEY = ""
|
|
10
|
+
|
|
11
|
+
credential = Credential(musicid=MUSICID, musickey=MUSICKEY)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def format_session_preview(index: int, session: PrivateMessageSession) -> str:
|
|
15
|
+
"""格式化私信会话预览."""
|
|
16
|
+
user = session.user
|
|
17
|
+
latest_message = session.new_msg
|
|
18
|
+
metadata = latest_message.meta_data if latest_message else None
|
|
19
|
+
latest_text = metadata.content if metadata and metadata.content else latest_message.tips if latest_message else ""
|
|
20
|
+
return (
|
|
21
|
+
f"{index}. session_id={session.session_id}, "
|
|
22
|
+
f"uin={user.uin if user else ''}, "
|
|
23
|
+
f"nick={user.nick if user else ''}, "
|
|
24
|
+
f"unread={session.new_msg_cnt}, "
|
|
25
|
+
f"last={latest_text or '<无文本预览>'}"
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
async def main() -> None:
|
|
30
|
+
"""运行私信只读接口示例."""
|
|
31
|
+
async with Client(credential) as client:
|
|
32
|
+
session_result = await client.private_message.get_sessions(size=10)
|
|
33
|
+
print(f"会话列表: has_more={session_result.has_more}, count={len(session_result.sessions)}")
|
|
34
|
+
|
|
35
|
+
if not session_result.sessions:
|
|
36
|
+
print("当前账号没有可展示的私信会话。")
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
print("可用会话:")
|
|
40
|
+
for index, session in enumerate(session_result.sessions, start=1):
|
|
41
|
+
print(format_session_preview(index, session))
|
|
42
|
+
|
|
43
|
+
first_session = session_result.sessions[0]
|
|
44
|
+
target_user = first_session.user
|
|
45
|
+
message_result = await client.private_message.get_messages(
|
|
46
|
+
session_id=first_session.session_id,
|
|
47
|
+
user_id=target_user.uin if target_user else "",
|
|
48
|
+
size=20,
|
|
49
|
+
)
|
|
50
|
+
print(f"首个会话消息: has_more={message_result.has_more}, count={len(message_result.messages)}")
|
|
51
|
+
|
|
52
|
+
entries_result = await client.private_message.get_chat_entries(
|
|
53
|
+
[1, 2],
|
|
54
|
+
from_user_type=0,
|
|
55
|
+
user_id=target_user.uin if target_user else None,
|
|
56
|
+
)
|
|
57
|
+
entry_count = sum(len(entries) for entries in entries_result.entries.values())
|
|
58
|
+
print(f"聊天入口: ret_code={entries_result.ret_code}, entry_count={entry_count}")
|
|
59
|
+
|
|
60
|
+
media_msg_ids = [
|
|
61
|
+
message.id for message in message_result.messages if message.id and message.msg_type in {2, 3, 5, 6}
|
|
62
|
+
]
|
|
63
|
+
if not media_msg_ids:
|
|
64
|
+
print("当前会话没有可用于预览详情查询的图片或视频消息。")
|
|
65
|
+
return
|
|
66
|
+
|
|
67
|
+
detail_result = await client.private_message.get_media_message_details(
|
|
68
|
+
first_session.session_id,
|
|
69
|
+
media_msg_ids[:5],
|
|
70
|
+
)
|
|
71
|
+
print(f"媒体消息详情: count={len(detail_result.msg_ids)}")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
asyncio.run(main())
|
|
@@ -32,6 +32,7 @@ if TYPE_CHECKING:
|
|
|
32
32
|
from ..modules.login import LoginApi
|
|
33
33
|
from ..modules.lyric import LyricApi
|
|
34
34
|
from ..modules.mv import MvApi
|
|
35
|
+
from ..modules.private_message import PrivateMessageApi
|
|
35
36
|
from ..modules.recommend import RecommendApi
|
|
36
37
|
from ..modules.search import SearchApi
|
|
37
38
|
from ..modules.singer import SingerApi
|
|
@@ -114,6 +115,13 @@ class Client:
|
|
|
114
115
|
|
|
115
116
|
return CommentApi(self)
|
|
116
117
|
|
|
118
|
+
@cached_property
|
|
119
|
+
def private_message(self) -> "PrivateMessageApi":
|
|
120
|
+
"""私信模块."""
|
|
121
|
+
from ..modules.private_message import PrivateMessageApi
|
|
122
|
+
|
|
123
|
+
return PrivateMessageApi(self)
|
|
124
|
+
|
|
117
125
|
@cached_property
|
|
118
126
|
def recommend(self) -> "RecommendApi":
|
|
119
127
|
"""推荐模块."""
|
|
@@ -279,7 +287,7 @@ class Client:
|
|
|
279
287
|
"""发送 API 请求."""
|
|
280
288
|
platform = Platform.ANDROID if is_jce else platform or self.platform
|
|
281
289
|
finalcomm = self._version_policy.build_comm(
|
|
282
|
-
platform=platform,
|
|
290
|
+
platform=platform or self.platform,
|
|
283
291
|
credential=credential or self.credential,
|
|
284
292
|
device=await self._device_store.get_device(),
|
|
285
293
|
qimei=cast("dict[str, str]", await self._qimei_manager.get_cached())
|
|
@@ -203,3 +203,23 @@ class MomentCommentResponse(Response):
|
|
|
203
203
|
hint: str = Field(alias="Hint")
|
|
204
204
|
prev_list_loaded: int = Field(alias="PrevListLoaded")
|
|
205
205
|
map_cm_ext: dict[str, dict[str, Any]] = Field(default_factory=dict, alias="MapCmExt")
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class AddCommentResponse(Response):
|
|
209
|
+
"""添加评论接口的响应体.
|
|
210
|
+
|
|
211
|
+
Attributes:
|
|
212
|
+
subcode: 响应子代码.
|
|
213
|
+
msg: 响应消息.
|
|
214
|
+
id: 新增评论 ID.
|
|
215
|
+
parent: 父评论 ID.
|
|
216
|
+
floor: 楼层号.
|
|
217
|
+
verify_url: 验证码 URL (如果需要).
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
subcode: int = Field(alias="SubCode")
|
|
221
|
+
msg: str = Field(alias="Msg")
|
|
222
|
+
id: str = Field(alias="AddedCmId")
|
|
223
|
+
parent: str = Field(alias="ParentCmId")
|
|
224
|
+
floor: int = Field(json_schema_extra={"jsonpath": "$.Floor.Num"})
|
|
225
|
+
verify_url: str = Field(alias="VerifyUrl")
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
"""私信模块返回模型定义."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import Field, field_validator, model_validator
|
|
6
|
+
|
|
7
|
+
from .request import Response
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PrivateMessageUser(Response):
|
|
11
|
+
"""私信用户信息.
|
|
12
|
+
|
|
13
|
+
Attributes:
|
|
14
|
+
avatar: 用户头像地址.
|
|
15
|
+
encrypt_uin: 加密 UIN.
|
|
16
|
+
uin: 用户 UIN.
|
|
17
|
+
identity_pic: 身份图标地址.
|
|
18
|
+
nick: 用户昵称.
|
|
19
|
+
identity: 身份标识.
|
|
20
|
+
type: 用户类型.
|
|
21
|
+
is_concern: 关注状态.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
avatar: str = ""
|
|
25
|
+
encrypt_uin: str = ""
|
|
26
|
+
uin: str = ""
|
|
27
|
+
identity_pic: str = ""
|
|
28
|
+
nick: str = ""
|
|
29
|
+
identity: int = -1
|
|
30
|
+
type: int = -1
|
|
31
|
+
is_concern: int = 0
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class PrivateMessageMetaData(Response):
|
|
35
|
+
"""私信消息元数据.
|
|
36
|
+
|
|
37
|
+
Attributes:
|
|
38
|
+
title: 卡片标题.
|
|
39
|
+
content: 文本内容或卡片正文.
|
|
40
|
+
pic: 图片地址.
|
|
41
|
+
biz_id: 业务 ID.
|
|
42
|
+
biz_type: 业务类型.
|
|
43
|
+
url: 跳转链接.
|
|
44
|
+
width: 媒体宽度.
|
|
45
|
+
height: 媒体高度.
|
|
46
|
+
duration: 媒体时长.
|
|
47
|
+
size: 媒体大小.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
title: str = ""
|
|
51
|
+
content: str = ""
|
|
52
|
+
pic: str = ""
|
|
53
|
+
biz_id: str = ""
|
|
54
|
+
biz_type: int = 0
|
|
55
|
+
url: str = ""
|
|
56
|
+
width: int = 0
|
|
57
|
+
height: int = 0
|
|
58
|
+
duration: int = Field(default=0, alias="Duration")
|
|
59
|
+
size: int = Field(default=0, alias="Size")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class PrivateMessageInfo(Response):
|
|
63
|
+
"""私信消息项.
|
|
64
|
+
|
|
65
|
+
Attributes:
|
|
66
|
+
id: 消息 ID.
|
|
67
|
+
meta_data: 消息元数据.
|
|
68
|
+
client_key: 客户端生成的消息键.
|
|
69
|
+
from_user: 发送方用户信息.
|
|
70
|
+
time: 消息时间戳.
|
|
71
|
+
state: 消息状态.
|
|
72
|
+
result: 发送结果.
|
|
73
|
+
tips: 提示文案.
|
|
74
|
+
sequence: 消息序列号.
|
|
75
|
+
show_type: 展示类型.
|
|
76
|
+
msg_type: 消息类型.
|
|
77
|
+
confirm: 确认状态.
|
|
78
|
+
sort_time: 排序时间戳.
|
|
79
|
+
complain_tip: 投诉提示文案.
|
|
80
|
+
complain_url: 投诉跳转链接.
|
|
81
|
+
"""
|
|
82
|
+
|
|
83
|
+
id: str = ""
|
|
84
|
+
meta_data: PrivateMessageMetaData | None = None
|
|
85
|
+
client_key: str = ""
|
|
86
|
+
from_user: PrivateMessageUser | None = None
|
|
87
|
+
time: int = 0
|
|
88
|
+
state: int = 0
|
|
89
|
+
result: int = 0
|
|
90
|
+
tips: str = ""
|
|
91
|
+
sequence: int = 0
|
|
92
|
+
show_type: int = 0
|
|
93
|
+
msg_type: int = 0
|
|
94
|
+
confirm: int = 0
|
|
95
|
+
sort_time: int = 0
|
|
96
|
+
complain_tip: str = Field(default="", alias="complainTip")
|
|
97
|
+
complain_url: str = Field(default="", alias="complainUrl")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class PrivateMessageTailTag(Response):
|
|
101
|
+
"""私信会话尾部标签.
|
|
102
|
+
|
|
103
|
+
Attributes:
|
|
104
|
+
data: 原始标签字段.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
data: dict[str, Any] = Field(default_factory=dict)
|
|
108
|
+
|
|
109
|
+
@model_validator(mode="before")
|
|
110
|
+
@classmethod
|
|
111
|
+
def _wrap_raw_tag(cls, data: Any) -> Any:
|
|
112
|
+
"""保留未建模的标签字段."""
|
|
113
|
+
if isinstance(data, dict) and "data" not in data:
|
|
114
|
+
return {"data": data}
|
|
115
|
+
return data
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class PrivateMessageSession(Response):
|
|
119
|
+
"""私信会话项.
|
|
120
|
+
|
|
121
|
+
Attributes:
|
|
122
|
+
session_id: 会话 ID.
|
|
123
|
+
user: 对端用户信息.
|
|
124
|
+
new_msg: 最新消息.
|
|
125
|
+
new_msg_cnt: 未读消息数.
|
|
126
|
+
sort_time: 排序时间戳.
|
|
127
|
+
url: 会话跳转链接.
|
|
128
|
+
create_time: 创建时间戳.
|
|
129
|
+
from_: 会话来源.
|
|
130
|
+
sm_star_virtual_uin: 超级私信虚拟 UIN.
|
|
131
|
+
auth: 授权信息.
|
|
132
|
+
ext: 扩展字段.
|
|
133
|
+
tail_tags: 尾部标签列表.
|
|
134
|
+
"""
|
|
135
|
+
|
|
136
|
+
session_id: str = ""
|
|
137
|
+
user: PrivateMessageUser | None = None
|
|
138
|
+
new_msg: PrivateMessageInfo | None = None
|
|
139
|
+
new_msg_cnt: int = 0
|
|
140
|
+
sort_time: int = 0
|
|
141
|
+
url: str = ""
|
|
142
|
+
create_time: int = Field(default=0, alias="create_time")
|
|
143
|
+
from_: int = Field(default=0, alias="from")
|
|
144
|
+
# 服务端字段名拼写如此, 保持 alias 与实际返回一致.
|
|
145
|
+
sm_star_virtual_uin: str = Field(default="", alias="SmStarVirtaulUin")
|
|
146
|
+
auth: str = Field(default="", alias="Auth")
|
|
147
|
+
ext: dict[str, str] = Field(default_factory=dict, alias="Ext")
|
|
148
|
+
tail_tags: list[PrivateMessageTailTag] = Field(default_factory=list, alias="TailTags")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class PrivateSessionListResponse(Response):
|
|
152
|
+
"""私信会话列表响应.
|
|
153
|
+
|
|
154
|
+
Attributes:
|
|
155
|
+
has_more: 是否还有更多会话.
|
|
156
|
+
msg: 提示文案.
|
|
157
|
+
new_msg_cnt: 未读消息数.
|
|
158
|
+
sessions: 会话列表.
|
|
159
|
+
subcode: 业务子码.
|
|
160
|
+
setting_guide: 设置引导标记.
|
|
161
|
+
state: 状态标记.
|
|
162
|
+
extra: 扩展字段.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
has_more: int = 0
|
|
166
|
+
msg: str = ""
|
|
167
|
+
new_msg_cnt: int = 0
|
|
168
|
+
sessions: list[PrivateMessageSession] = Field(default_factory=list)
|
|
169
|
+
subcode: int = 0
|
|
170
|
+
setting_guide: int = 0
|
|
171
|
+
state: int = 0
|
|
172
|
+
extra: dict[str, str] = Field(default_factory=dict)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class PrivateMessagePatText(Response):
|
|
176
|
+
"""拍一拍文案信息.
|
|
177
|
+
|
|
178
|
+
Attributes:
|
|
179
|
+
nick: 用户昵称.
|
|
180
|
+
pat_text: 拍一拍文案.
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
nick: str = Field(default="", alias="Nick")
|
|
184
|
+
pat_text: str = Field(default="", alias="PatTxt")
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class PrivateMessageListResponse(Response):
|
|
188
|
+
"""私信消息列表响应.
|
|
189
|
+
|
|
190
|
+
Attributes:
|
|
191
|
+
has_more: 是否还有更多消息.
|
|
192
|
+
messages: 消息列表.
|
|
193
|
+
msg: 提示文案.
|
|
194
|
+
session: 会话信息.
|
|
195
|
+
subcode: 业务子码.
|
|
196
|
+
end_msg_seq: 结束消息序列号.
|
|
197
|
+
attach: 附加字段.
|
|
198
|
+
pat_interval: 拍一拍间隔.
|
|
199
|
+
pat_map: 拍一拍文案映射.
|
|
200
|
+
encrypt_star: 加密明星 UIN.
|
|
201
|
+
location_tips: 定位提示文案.
|
|
202
|
+
new_msg_cnt: 新消息数量.
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
has_more: int = 0
|
|
206
|
+
messages: list[PrivateMessageInfo] = Field(default_factory=list)
|
|
207
|
+
msg: str = ""
|
|
208
|
+
session: PrivateMessageSession | None = None
|
|
209
|
+
subcode: int = 0
|
|
210
|
+
end_msg_seq: int = 0
|
|
211
|
+
attach: dict[str, Any] = Field(default_factory=dict, alias="Attach")
|
|
212
|
+
pat_interval: int = Field(default=0, alias="PatInterval")
|
|
213
|
+
pat_map: dict[str, PrivateMessagePatText] = Field(default_factory=dict, alias="PatMap")
|
|
214
|
+
encrypt_star: str = Field(default="", alias="EncryptStar")
|
|
215
|
+
location_tips: str = Field(default="", alias="LocationTips")
|
|
216
|
+
new_msg_cnt: int = Field(default=0, alias="NewMsgCnt")
|
|
217
|
+
|
|
218
|
+
@field_validator("attach", "pat_map", mode="before")
|
|
219
|
+
@classmethod
|
|
220
|
+
def _normalize_nullable_fields(cls, value: Any) -> Any:
|
|
221
|
+
"""将服务端返回的空映射归一为空字典."""
|
|
222
|
+
return {} if value is None else value
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class PrivateSendMessageResponse(Response):
|
|
226
|
+
"""私信发送响应.
|
|
227
|
+
|
|
228
|
+
Attributes:
|
|
229
|
+
messages: 服务端返回的消息列表.
|
|
230
|
+
session: 会话信息.
|
|
231
|
+
tips: 提示文案.
|
|
232
|
+
identify_url: 实名认证跳转链接.
|
|
233
|
+
msg: 业务提示.
|
|
234
|
+
reason: 失败原因码.
|
|
235
|
+
end_msg_seq: 结束消息序列号.
|
|
236
|
+
update_time: 更新时间戳.
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
messages: list[PrivateMessageInfo] = Field(default_factory=list)
|
|
240
|
+
session: PrivateMessageSession | None = None
|
|
241
|
+
tips: str = ""
|
|
242
|
+
identify_url: str = ""
|
|
243
|
+
msg: str = ""
|
|
244
|
+
reason: int = 0
|
|
245
|
+
end_msg_seq: int = 0
|
|
246
|
+
update_time: int = 0
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class PrivateOperationResponse(Response):
|
|
250
|
+
"""私信写操作响应.
|
|
251
|
+
|
|
252
|
+
Attributes:
|
|
253
|
+
msg: 提示文案.
|
|
254
|
+
subcode: 业务子码.
|
|
255
|
+
tips: 失败提示.
|
|
256
|
+
"""
|
|
257
|
+
|
|
258
|
+
msg: str = ""
|
|
259
|
+
subcode: int = 0
|
|
260
|
+
tips: str = ""
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class PrivateConfigResponse(Response):
|
|
264
|
+
"""私信配置读取响应.
|
|
265
|
+
|
|
266
|
+
Attributes:
|
|
267
|
+
config_value: 配置值.
|
|
268
|
+
config_value_str: 配置字符串值.
|
|
269
|
+
msg: 提示文案.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
config_value: int = 0
|
|
273
|
+
config_value_str: str = ""
|
|
274
|
+
msg: str = ""
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class PrivateMusicianCardResponse(Response):
|
|
278
|
+
"""音乐人卡片响应.
|
|
279
|
+
|
|
280
|
+
Attributes:
|
|
281
|
+
data: 未建模的卡片原始字段.
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
data: dict[str, Any] = Field(default_factory=dict)
|
|
285
|
+
|
|
286
|
+
@model_validator(mode="before")
|
|
287
|
+
@classmethod
|
|
288
|
+
def _wrap_raw_card(cls, data: Any) -> Any:
|
|
289
|
+
"""保留未建模的卡片字段."""
|
|
290
|
+
if isinstance(data, dict) and "data" not in data:
|
|
291
|
+
return {"data": data}
|
|
292
|
+
return data
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
class PrivateEntryItem(Response):
|
|
296
|
+
"""聊天页入口项.
|
|
297
|
+
|
|
298
|
+
Attributes:
|
|
299
|
+
entry_type: 入口类型.
|
|
300
|
+
icon: 图标地址.
|
|
301
|
+
title: 标题.
|
|
302
|
+
skip_scheme: 跳转 Scheme.
|
|
303
|
+
right_top_tag: 右上角标签.
|
|
304
|
+
ext: 扩展字段.
|
|
305
|
+
"""
|
|
306
|
+
|
|
307
|
+
entry_type: int = Field(default=-1, alias="EntryType")
|
|
308
|
+
icon: str = Field(default="", alias="Icon")
|
|
309
|
+
title: str = Field(default="", alias="Title")
|
|
310
|
+
skip_scheme: str = Field(default="", alias="SkipScheme")
|
|
311
|
+
right_top_tag: str = Field(default="", alias="RightTopTag")
|
|
312
|
+
ext: dict[str, str] = Field(default_factory=dict, alias="Ext")
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
class PrivateChatEntriesResponse(Response):
|
|
316
|
+
"""聊天页入口响应.
|
|
317
|
+
|
|
318
|
+
Attributes:
|
|
319
|
+
ret_code: 返回码.
|
|
320
|
+
ret_msg: 返回文案.
|
|
321
|
+
entries: 按场景分组的入口列表.
|
|
322
|
+
can_be_dazi: 是否可成为搭子.
|
|
323
|
+
dz_data: 未建模的搭子入口字段.
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
ret_code: int = Field(default=0, alias="RetCode")
|
|
327
|
+
ret_msg: str = Field(default="", alias="RetMsg")
|
|
328
|
+
entries: dict[int, list[PrivateEntryItem]] = Field(default_factory=dict, alias="Entries")
|
|
329
|
+
can_be_dazi: bool | None = Field(default=None, alias="CanBeDazi")
|
|
330
|
+
dz_data: dict[str, Any] = Field(default_factory=dict, alias="DzData")
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class PrivateMediaMessageDetailsResponse(Response):
|
|
334
|
+
"""图片和视频消息详情响应.
|
|
335
|
+
|
|
336
|
+
Attributes:
|
|
337
|
+
msg_ids: 消息 ID 到消息详情的映射.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
msg_ids: dict[str, PrivateMessageInfo] = Field(default_factory=dict, alias="MsgIDs")
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class PrivateSafetyHintResponse(Response):
|
|
344
|
+
"""私信安全提示响应.
|
|
345
|
+
|
|
346
|
+
Attributes:
|
|
347
|
+
hint: 安全提示文案.
|
|
348
|
+
"""
|
|
349
|
+
|
|
350
|
+
hint: str = ""
|
|
@@ -5,6 +5,7 @@ from .comment import CommentApi
|
|
|
5
5
|
from .login import LoginApi
|
|
6
6
|
from .lyric import LyricApi
|
|
7
7
|
from .mv import MvApi
|
|
8
|
+
from .private_message import PrivateMessageApi
|
|
8
9
|
from .recommend import RecommendApi
|
|
9
10
|
from .search import SearchApi
|
|
10
11
|
from .singer import SingerApi
|
|
@@ -19,6 +20,7 @@ __all__ = [
|
|
|
19
20
|
"LoginApi",
|
|
20
21
|
"LyricApi",
|
|
21
22
|
"MvApi",
|
|
23
|
+
"PrivateMessageApi",
|
|
22
24
|
"RecommendApi",
|
|
23
25
|
"SearchApi",
|
|
24
26
|
"SingerApi",
|
|
@@ -9,7 +9,9 @@ from ..core.pagination import (
|
|
|
9
9
|
PaginationParams,
|
|
10
10
|
ResponseAdapter,
|
|
11
11
|
)
|
|
12
|
-
from ..
|
|
12
|
+
from ..core.versioning import Platform
|
|
13
|
+
from ..models.comment import AddCommentResponse, CommentCountResponse, CommentListResponse, MomentCommentResponse
|
|
14
|
+
from ..models.request import Credential
|
|
13
15
|
from ._base import ApiModule
|
|
14
16
|
|
|
15
17
|
|
|
@@ -48,6 +50,7 @@ class CommentApi(ApiModule):
|
|
|
48
50
|
Args:
|
|
49
51
|
biz_id: 歌曲 ID.
|
|
50
52
|
"""
|
|
53
|
+
# 支持 request_list
|
|
51
54
|
data = {
|
|
52
55
|
"request": {
|
|
53
56
|
"biz_id": str(biz_id),
|
|
@@ -194,3 +197,59 @@ class CommentApi(ApiModule):
|
|
|
194
197
|
adapter=ResponseAdapter(has_more_flag="has_more", cursor="next_pos"),
|
|
195
198
|
),
|
|
196
199
|
)
|
|
200
|
+
|
|
201
|
+
def add_comment(
|
|
202
|
+
self,
|
|
203
|
+
biz_id: int,
|
|
204
|
+
content: str,
|
|
205
|
+
reply_cmt_id: str | None = None,
|
|
206
|
+
credential: Credential | None = None,
|
|
207
|
+
):
|
|
208
|
+
"""添加评论.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
biz_id: 歌曲 ID.
|
|
212
|
+
content: 评论内容.
|
|
213
|
+
reply_cmt_id: 回复的评论 ID.
|
|
214
|
+
credential: 登录凭据.
|
|
215
|
+
"""
|
|
216
|
+
self._require_login(credential)
|
|
217
|
+
return self._build_request(
|
|
218
|
+
"music.globalComment.CommentWriteServer",
|
|
219
|
+
"AddComment",
|
|
220
|
+
{
|
|
221
|
+
"Content": content,
|
|
222
|
+
"BizType": 1,
|
|
223
|
+
"BizId": str(biz_id),
|
|
224
|
+
"RepliedCmId": reply_cmt_id,
|
|
225
|
+
},
|
|
226
|
+
credential=credential,
|
|
227
|
+
platform=Platform.ANDROID,
|
|
228
|
+
response_model=AddCommentResponse,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
async def delete_comment(
|
|
232
|
+
self,
|
|
233
|
+
cm_id: str,
|
|
234
|
+
credential: Credential | None = None,
|
|
235
|
+
) -> bool:
|
|
236
|
+
"""删除评论.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
cm_id: 评论 ID.
|
|
240
|
+
credential: 登录凭据.
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
是否删除成功,评论不存在也为 True.
|
|
244
|
+
"""
|
|
245
|
+
self._require_login(credential)
|
|
246
|
+
data = await self._build_request(
|
|
247
|
+
"music.globalComment.CommentWriteServer",
|
|
248
|
+
"DelComment",
|
|
249
|
+
{
|
|
250
|
+
"CommentId": cm_id,
|
|
251
|
+
},
|
|
252
|
+
platform=Platform.ANDROID,
|
|
253
|
+
credential=credential,
|
|
254
|
+
)
|
|
255
|
+
return data.get("SubCode", 0) == 0
|