qqmusic-api-python 0.8.1__tar.gz → 0.8.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/PKG-INFO +1 -1
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/release-notes.md +26 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/pyproject.toml +0 -1
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/__init__.py +1 -1
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/singer.py +76 -14
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/singer.py +111 -16
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_singer.py +44 -6
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/typing/test_client_typing.py +7 -3
- qqmusic_api_python-0.8.2/uv.lock +2243 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/README.md +1 -1
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/config.example.toml +0 -12
- qqmusic_api_python-0.8.2/web/requirements.txt +1565 -0
- qqmusic_api_python-0.8.2/web/run.py +39 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/app.py +0 -30
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/config.py +0 -14
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/login.py +0 -1
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/mv.py +0 -10
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/_helpers.py +1 -37
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/mv.py +3 -5
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/singer.py +8 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/adapter_registry.py +0 -5
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/route_types.py +1 -3
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/router_factory.py +3 -5
- qqmusic_api_python-0.8.1/uv.lock +0 -2083
- qqmusic_api_python-0.8.1/web/requirements.txt +0 -1407
- qqmusic_api_python-0.8.1/web/run.py +0 -105
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.agents/skills/pydantic/SKILL.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.agents/skills/python-standards/SKILL.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.agents/skills/uv-package-manager/SKILL.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.dockerignore +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/renovate.json +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/workflows/checking.yaml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/workflows/docs.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/workflows/release.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.github/workflows/testing.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.gitignore +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/.markdownlint-cli2.yaml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/AGENTS.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/CLAUDE.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/LICENSE +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/README.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/assets/qq-music.svg +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/cliff.toml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/coding.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/contributing.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/index.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/core/client.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/core/exception.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/core/pagination.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/core/request.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/core/versioning.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/album.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/base.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/comment.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/helper.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/login.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/lyric.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/mv.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/private_message.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/recommend.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/request.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/search.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/singer.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/song.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/songlist.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/sound_power.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/top.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/model/user.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/album.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/comment.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/helper.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/helper_utils.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/login.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/login_utils.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/lyric.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/mv.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/private_message.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/recommend.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/search.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/singer.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/song.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/songlist.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/sound_power.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/top.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/reference/modules/user.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/client.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/credential.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/download.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/error-handling.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/login.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/pagination.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/start.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/docs/tutorial/web.md +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/download_song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/get_all_sheets.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/phone_login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/private_message.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/qrcode_login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/sound_power.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/examples/upload_file.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/prek.toml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/algorithms/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/algorithms/sign.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/algorithms/tripledes.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/client.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/endpoint.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/engine.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/exceptions.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/executor.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/pagination.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/request.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/response.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/transport.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/core/versioning.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/_validator.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/album.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/base.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/comment.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/helper.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/lyric.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/mv.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/private_message.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/recommend.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/request.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/search.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/songlist.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/sound_power.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/top.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/models/user.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/_base.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/album.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/comment.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/helper.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/helper_utils.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/login_utils.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/lyric.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/mv.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/private_message.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/recommend.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/search.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/songlist.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/sound_power.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/top.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/modules/user.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/py.typed +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/android_session.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/common.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/device.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/mqtt.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/qqmusic_api/utils/qimei.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/scripts/ag-1.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/conftest.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/kernel_contract.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_album.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_android_session.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_client.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_comment.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_device.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_endpoint.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_engine.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_executor.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_login_engine.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_login_utils.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_lyric.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_mv.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_pagination.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_private_message.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_qimei.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_recommend.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_response.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_search.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_songlist.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_sound_power.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_top.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_transport.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/test_user.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/typing/test_build_request.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/tests/typing/test_endpoint_typing.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/.gitignore +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/Dockerfile +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/accounts.example.toml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/docker-compose.example.yml +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/auth.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/cache.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/coalesce.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/credential_pool.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/credential_store.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/deps.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/error_mapping.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/response.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/core/security.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/comment.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/singer.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/modules/songlist.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/album.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/comment.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/login.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/lyric.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/recommend.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/search.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/song.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/songlist.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/sound_power.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/top.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routes/user.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/__init__.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/docstrings.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/executor.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/modules.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/src/routing/params.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/conftest.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_core.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_docstrings.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_engine_services.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_enums.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_route_validation.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/web/tests/test_web_routes.py +0 -0
- {qqmusic_api_python-0.8.1 → qqmusic_api_python-0.8.2}/zensical.toml +0 -0
|
@@ -1,4 +1,30 @@
|
|
|
1
1
|
|
|
2
|
+
## [[0.8.1](https://github.com/L-1124/QQMusicApi/compare/v0.8.0..v0.8.1)] - 2026-10-04
|
|
3
|
+
|
|
4
|
+
### Bug 修复
|
|
5
|
+
|
|
6
|
+
* **(core)** 为传输层增加默认请求超时 ([86a2716](https://github.com/L-1124/QQMusicApi/commit/86a2716eddde166edcacfe511d4b9f2090f6a2bd)) by [@L-1124](https://github.com/L-1124)
|
|
7
|
+
* **(web)** 手机验证码路由改为 POST 提交 ([b714255](https://github.com/L-1124/QQMusicApi/commit/b714255b2a9dbef535e709659fd029b49856bbf6)) by [@L-1124](https://github.com/L-1124)
|
|
8
|
+
* **(web)** 参数校验失败响应返回错误详情 ([dee7e18](https://github.com/L-1124/QQMusicApi/commit/dee7e187c26a45b973759f56c7445da635e04740)) by [@L-1124](https://github.com/L-1124)
|
|
9
|
+
|
|
10
|
+
### 功能更新
|
|
11
|
+
|
|
12
|
+
* **(core)** 新增 Credential.is_valid 并收编登录态判断 ([415b3ae](https://github.com/L-1124/QQMusicApi/commit/415b3aef6e3f3b7fc5092653f22c1ce0d5dc31d5)) by [@L-1124](https://github.com/L-1124)
|
|
13
|
+
* **(core)** 补充 py.typed 类型标记 ([2136321](https://github.com/L-1124/QQMusicApi/commit/2136321cf19796e0738f6b91243a650dd99f76a2)) by [@L-1124](https://github.com/L-1124)
|
|
14
|
+
|
|
15
|
+
### 功能重构
|
|
16
|
+
|
|
17
|
+
* **(web)** 复用 Credential.is_valid 移除重复登录态判断 ([f8ec18d](https://github.com/L-1124/QQMusicApi/commit/f8ec18dcf9a559988ff141972b704861a3a5ef5e)) by [@L-1124](https://github.com/L-1124)
|
|
18
|
+
|
|
19
|
+
### 文档更新
|
|
20
|
+
|
|
21
|
+
* 修正刷新凭证示例与 Web 服务启动说明 ([83e743b](https://github.com/L-1124/QQMusicApi/commit/83e743b52219471ddb399e21d6a003273f2c0bd2)) by [@L-1124](https://github.com/L-1124)
|
|
22
|
+
|
|
23
|
+
### 贡献者
|
|
24
|
+
|
|
25
|
+
* @L-1124
|
|
26
|
+
* @github-actions[bot]
|
|
27
|
+
|
|
2
28
|
## [[0.8.0](https://github.com/L-1124/QQMusicApi/compare/v0.7.3..v0.8.0)] - 2026-10-04
|
|
3
29
|
|
|
4
30
|
### Bug 修复
|
|
@@ -234,6 +234,74 @@ class VideoBrief(MV):
|
|
|
234
234
|
icon_type: int = 0
|
|
235
235
|
|
|
236
236
|
|
|
237
|
+
class TabFilterItem(Response):
|
|
238
|
+
"""Tab 筛选条目 (专辑类型 / 视频标签).
|
|
239
|
+
|
|
240
|
+
Attributes:
|
|
241
|
+
id: 筛选项 ID.
|
|
242
|
+
title: 筛选项名称.
|
|
243
|
+
"""
|
|
244
|
+
|
|
245
|
+
id: int = Field(default=-1, validation_alias=AliasChoices("ID", "id"))
|
|
246
|
+
title: str = Field(default="", validation_alias=AliasChoices("Title", "name"))
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class TabFilterList(Response):
|
|
250
|
+
"""服务端下发的 Tab 筛选列表.
|
|
251
|
+
|
|
252
|
+
Attributes:
|
|
253
|
+
default_id: 默认选中项 ID.
|
|
254
|
+
items: 筛选项列表.
|
|
255
|
+
"""
|
|
256
|
+
|
|
257
|
+
default_id: int = Field(default=0, validation_alias="DefaultID")
|
|
258
|
+
items: Annotated[list[TabFilterItem], NoneToEmptyList] = Field(default_factory=list, validation_alias="ItemList")
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class SongTabInfo(Response):
|
|
262
|
+
"""歌曲 Tab 内容.
|
|
263
|
+
|
|
264
|
+
Attributes:
|
|
265
|
+
songs: 歌曲列表.
|
|
266
|
+
tag_info_list: 歌曲标签信息列表 (客户端原样透传).
|
|
267
|
+
"""
|
|
268
|
+
|
|
269
|
+
songs: Annotated[list[Song], NoneToEmptyList] = Field(
|
|
270
|
+
default_factory=list, json_schema_extra={"jsonpath": "$.List[*]"}
|
|
271
|
+
)
|
|
272
|
+
tag_info_list: Annotated[list[dict[str, Any]], NoneToEmptyList] = Field(
|
|
273
|
+
default_factory=list, validation_alias="SongTagInfoList"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class AlbumTabInfo(Response):
|
|
278
|
+
"""专辑 Tab 内容.
|
|
279
|
+
|
|
280
|
+
Attributes:
|
|
281
|
+
type_list: 服务端下发的专辑分类筛选列表.
|
|
282
|
+
albums: 专辑列表.
|
|
283
|
+
"""
|
|
284
|
+
|
|
285
|
+
type_list: TabFilterList = Field(default_factory=TabFilterList, validation_alias="TypeList")
|
|
286
|
+
albums: Annotated[list[AlbumBrief], NoneToEmptyList] = Field(
|
|
287
|
+
default_factory=list, json_schema_extra={"jsonpath": "$.AlbumList[*]"}
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
class VideoTabInfo(Response):
|
|
292
|
+
"""视频 Tab 内容.
|
|
293
|
+
|
|
294
|
+
Attributes:
|
|
295
|
+
videos: 视频列表.
|
|
296
|
+
tag_list: 服务端下发的视频标签筛选列表.
|
|
297
|
+
"""
|
|
298
|
+
|
|
299
|
+
videos: Annotated[list[VideoBrief], NoneToEmptyList] = Field(
|
|
300
|
+
default_factory=list, json_schema_extra={"jsonpath": "$.VideoList[*]"}
|
|
301
|
+
)
|
|
302
|
+
tag_list: Annotated[list[TabFilterItem], NoneToEmptyList] = Field(default_factory=list, validation_alias="TagList")
|
|
303
|
+
|
|
304
|
+
|
|
237
305
|
class HomepageTabDetailResponse(Response):
|
|
238
306
|
"""歌手主页标签详情响应.
|
|
239
307
|
|
|
@@ -241,12 +309,12 @@ class HomepageTabDetailResponse(Response):
|
|
|
241
309
|
tab_id: 当前标签页 ID.
|
|
242
310
|
has_more: 是否还有更多结果.
|
|
243
311
|
need_show_tab: 是否需要展示标签.
|
|
244
|
-
order:
|
|
312
|
+
order: 服务端归一化后的排序值.
|
|
245
313
|
tab_list: 标签页元信息列表.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
314
|
+
song_tab: 歌曲 Tab 内容.
|
|
315
|
+
album_tab: 专辑 Tab 内容.
|
|
316
|
+
video_tab: 视频 Tab 内容.
|
|
317
|
+
introduction_tab: 简介 Tab 内容.
|
|
250
318
|
"""
|
|
251
319
|
|
|
252
320
|
tab_id: str = Field(default="", validation_alias="TabID")
|
|
@@ -254,19 +322,13 @@ class HomepageTabDetailResponse(Response):
|
|
|
254
322
|
need_show_tab: int = Field(default=0, validation_alias="NeedShowTab")
|
|
255
323
|
order: int = Field(default=0, validation_alias="Order")
|
|
256
324
|
tab_list: Annotated[list[TabMeta], NoneToEmptyList] = Field(default_factory=list, validation_alias="TabList")
|
|
325
|
+
song_tab: SongTabInfo = Field(default_factory=SongTabInfo, validation_alias="SongTab")
|
|
326
|
+
album_tab: AlbumTabInfo = Field(default_factory=AlbumTabInfo, validation_alias="AlbumTab")
|
|
327
|
+
video_tab: VideoTabInfo = Field(default_factory=VideoTabInfo, validation_alias="VideoTab")
|
|
257
328
|
introduction_tab: Annotated[list[dict[str, Any]], NoneToEmptyList] = Field(
|
|
258
329
|
default_factory=list,
|
|
259
330
|
json_schema_extra={"jsonpath": "$.IntroductionTab.List"},
|
|
260
331
|
)
|
|
261
|
-
song_tab: Annotated[list[Song], NoneToEmptyList] = Field(
|
|
262
|
-
default_factory=list, json_schema_extra={"jsonpath": "$.SongTab.List[*]"}
|
|
263
|
-
)
|
|
264
|
-
album_tab: Annotated[list[AlbumBrief], NoneToEmptyList] = Field(
|
|
265
|
-
default_factory=list, json_schema_extra={"jsonpath": "$.AlbumTab.AlbumList[*]"}
|
|
266
|
-
)
|
|
267
|
-
video_tab: Annotated[list[VideoBrief], NoneToEmptyList] = Field(
|
|
268
|
-
default_factory=list, json_schema_extra={"jsonpath": "$.VideoTab.VideoList[*]"}
|
|
269
|
-
)
|
|
270
332
|
|
|
271
333
|
|
|
272
334
|
class HomepageHeaderResponse(Response):
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"""歌手相关 API."""
|
|
2
2
|
|
|
3
3
|
from enum import Enum, IntEnum
|
|
4
|
-
from typing import cast
|
|
4
|
+
from typing import Any, Literal, TypedDict, cast, overload
|
|
5
5
|
|
|
6
|
-
from ..core import Platform
|
|
6
|
+
from ..core import PaginatedCgiRequest, Platform
|
|
7
7
|
from ..core.endpoint import CgiRequestData, cgi_endpoint
|
|
8
8
|
from ..core.pagination import (
|
|
9
9
|
MultiFieldContinuationStrategy,
|
|
@@ -91,6 +91,17 @@ class TabType(Enum):
|
|
|
91
91
|
self.tab_name = tab_name
|
|
92
92
|
|
|
93
93
|
|
|
94
|
+
class OrderType(IntEnum):
|
|
95
|
+
"""歌手主页条目排序类型.
|
|
96
|
+
|
|
97
|
+
+ LATEST: 最新 / 按时间排序 (0)
|
|
98
|
+
+ HOT: 最热 / 按热度排序 (1)
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
LATEST = 0
|
|
102
|
+
HOT = 1
|
|
103
|
+
|
|
104
|
+
|
|
94
105
|
class IndexType(IntEnum):
|
|
95
106
|
"""首字母索引枚举."""
|
|
96
107
|
|
|
@@ -124,6 +135,30 @@ class IndexType(IntEnum):
|
|
|
124
135
|
HASH = 27
|
|
125
136
|
|
|
126
137
|
|
|
138
|
+
class AlbumExtension(TypedDict):
|
|
139
|
+
"""专辑 Tab 扩展参数.
|
|
140
|
+
|
|
141
|
+
Attributes:
|
|
142
|
+
IsNeedFilterType: 是否下发分类筛选列表.
|
|
143
|
+
FilterType: 分类筛选值.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
IsNeedFilterType: int
|
|
147
|
+
FilterType: int
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class VideoExtension(TypedDict):
|
|
151
|
+
"""视频 Tab 扩展参数.
|
|
152
|
+
|
|
153
|
+
Attributes:
|
|
154
|
+
TagID: 视频标签筛选值.
|
|
155
|
+
IsNeedTagList: 是否下发标签列表.
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
TagID: int
|
|
159
|
+
IsNeedTagList: int
|
|
160
|
+
|
|
161
|
+
|
|
127
162
|
class SingerApi(ApiModule):
|
|
128
163
|
"""歌手相关 API."""
|
|
129
164
|
|
|
@@ -224,6 +259,38 @@ class SingerApi(ApiModule):
|
|
|
224
259
|
param={"SingerMid": mid},
|
|
225
260
|
)
|
|
226
261
|
|
|
262
|
+
@overload
|
|
263
|
+
def get_tab_detail(
|
|
264
|
+
self,
|
|
265
|
+
mid: str,
|
|
266
|
+
tab_type: Literal[TabType.VIDEO],
|
|
267
|
+
page: int = 1,
|
|
268
|
+
num: int = 10,
|
|
269
|
+
order: OrderType | int = OrderType.LATEST,
|
|
270
|
+
extension: VideoExtension | None = None,
|
|
271
|
+
) -> PaginatedCgiRequest[HomepageTabDetailResponse]: ...
|
|
272
|
+
|
|
273
|
+
@overload
|
|
274
|
+
def get_tab_detail(
|
|
275
|
+
self,
|
|
276
|
+
mid: str,
|
|
277
|
+
tab_type: Literal[TabType.ALBUM],
|
|
278
|
+
page: int = 1,
|
|
279
|
+
num: int = 10,
|
|
280
|
+
order: OrderType | int = OrderType.LATEST,
|
|
281
|
+
extension: AlbumExtension | None = None,
|
|
282
|
+
) -> PaginatedCgiRequest[HomepageTabDetailResponse]: ...
|
|
283
|
+
|
|
284
|
+
@overload
|
|
285
|
+
def get_tab_detail(
|
|
286
|
+
self,
|
|
287
|
+
mid: str,
|
|
288
|
+
tab_type: TabType,
|
|
289
|
+
page: int = 1,
|
|
290
|
+
num: int = 10,
|
|
291
|
+
order: OrderType | int = OrderType.LATEST,
|
|
292
|
+
) -> PaginatedCgiRequest[HomepageTabDetailResponse]: ...
|
|
293
|
+
|
|
227
294
|
@cgi_endpoint(
|
|
228
295
|
key="singer.get_tab_detail",
|
|
229
296
|
module="music.UnifiedHomepage.UnifiedHomepageSrv",
|
|
@@ -237,6 +304,8 @@ class SingerApi(ApiModule):
|
|
|
237
304
|
tab_type: TabType,
|
|
238
305
|
page: int = 1,
|
|
239
306
|
num: int = 10,
|
|
307
|
+
order: OrderType | int = OrderType.LATEST,
|
|
308
|
+
extension: VideoExtension | AlbumExtension | None = None,
|
|
240
309
|
) -> CgiRequestData:
|
|
241
310
|
"""获取歌手主页特定 Tab 的详情原始数据.
|
|
242
311
|
|
|
@@ -245,16 +314,21 @@ class SingerApi(ApiModule):
|
|
|
245
314
|
tab_type: Tab 类型.
|
|
246
315
|
page: 页码.
|
|
247
316
|
num: 返回数量.
|
|
317
|
+
order: 排序方式 (最新 / 最热).
|
|
318
|
+
extension: Tab 请求扩展参数.
|
|
248
319
|
"""
|
|
320
|
+
param: dict[str, Any] = {
|
|
321
|
+
"SingerMid": mid,
|
|
322
|
+
"IsQueryTabDetail": 1,
|
|
323
|
+
"TabID": tab_type.tab_id,
|
|
324
|
+
"PageNum": page - 1,
|
|
325
|
+
"PageSize": num,
|
|
326
|
+
"Order": int(order),
|
|
327
|
+
}
|
|
328
|
+
if extension:
|
|
329
|
+
param[tab_type.value[1].replace("Tab", "") + "Extension"] = extension
|
|
249
330
|
return CgiRequestData(
|
|
250
|
-
param=
|
|
251
|
-
"SingerMid": mid,
|
|
252
|
-
"IsQueryTabDetail": 1,
|
|
253
|
-
"TabID": tab_type.tab_id,
|
|
254
|
-
"PageNum": page - 1,
|
|
255
|
-
"PageSize": num,
|
|
256
|
-
"Order": 0,
|
|
257
|
-
},
|
|
331
|
+
param=param,
|
|
258
332
|
pager_strategy=PageStrategy[HomepageTabDetailResponse](
|
|
259
333
|
page_key="PageNum",
|
|
260
334
|
page_size=num,
|
|
@@ -324,16 +398,23 @@ class SingerApi(ApiModule):
|
|
|
324
398
|
response_model=SingerSongListResponse,
|
|
325
399
|
item_type=Song,
|
|
326
400
|
)
|
|
327
|
-
def get_songs_list(
|
|
401
|
+
def get_songs_list(
|
|
402
|
+
self,
|
|
403
|
+
mid: str,
|
|
404
|
+
num: int = 10,
|
|
405
|
+
page: int = 1,
|
|
406
|
+
order: OrderType | int = OrderType.HOT,
|
|
407
|
+
) -> CgiRequestData:
|
|
328
408
|
"""获取歌手的歌曲列表.
|
|
329
409
|
|
|
330
410
|
Args:
|
|
331
411
|
mid: 歌手 MID.
|
|
332
412
|
num: 返回歌曲数量.
|
|
333
413
|
page: 分页页码.
|
|
414
|
+
order: 排序方式.
|
|
334
415
|
"""
|
|
335
416
|
return CgiRequestData(
|
|
336
|
-
param={"singerMid": mid, "order":
|
|
417
|
+
param={"singerMid": mid, "order": int(order), "number": num, "begin": (page - 1) * num},
|
|
337
418
|
pager_strategy=OffsetStrategy[SingerSongListResponse](
|
|
338
419
|
offset_key="begin",
|
|
339
420
|
page_size_key="number",
|
|
@@ -350,16 +431,23 @@ class SingerApi(ApiModule):
|
|
|
350
431
|
response_model=SingerAlbumListResponse,
|
|
351
432
|
item_type=AlbumBrief,
|
|
352
433
|
)
|
|
353
|
-
def get_album_list(
|
|
434
|
+
def get_album_list(
|
|
435
|
+
self,
|
|
436
|
+
mid: str,
|
|
437
|
+
num: int = 10,
|
|
438
|
+
page: int = 1,
|
|
439
|
+
order: OrderType | int = OrderType.HOT,
|
|
440
|
+
) -> CgiRequestData:
|
|
354
441
|
"""获取歌手的专辑列表.
|
|
355
442
|
|
|
356
443
|
Args:
|
|
357
444
|
mid: 歌手 MID.
|
|
358
445
|
num: 返回专辑数量.
|
|
359
446
|
page: 分页页码.
|
|
447
|
+
order: 排序方式.
|
|
360
448
|
"""
|
|
361
449
|
return CgiRequestData(
|
|
362
|
-
param={"singerMid": mid, "order":
|
|
450
|
+
param={"singerMid": mid, "order": int(order), "number": num, "begin": (page - 1) * num},
|
|
363
451
|
pager_strategy=OffsetStrategy[SingerAlbumListResponse](
|
|
364
452
|
offset_key="begin",
|
|
365
453
|
page_size_key="number",
|
|
@@ -376,16 +464,23 @@ class SingerApi(ApiModule):
|
|
|
376
464
|
response_model=SingerMvListResponse,
|
|
377
465
|
item_type=VideoBrief,
|
|
378
466
|
)
|
|
379
|
-
def get_mv_list(
|
|
467
|
+
def get_mv_list(
|
|
468
|
+
self,
|
|
469
|
+
mid: str,
|
|
470
|
+
num: int = 10,
|
|
471
|
+
page: int = 1,
|
|
472
|
+
order: OrderType | int = OrderType.HOT,
|
|
473
|
+
) -> CgiRequestData:
|
|
380
474
|
"""获取歌手 MV 列表数据.
|
|
381
475
|
|
|
382
476
|
Args:
|
|
383
477
|
mid: 歌手 MID.
|
|
384
478
|
num: 返回数量.
|
|
385
479
|
page: 分页页码.
|
|
480
|
+
order: 排序方式.
|
|
386
481
|
"""
|
|
387
482
|
return CgiRequestData(
|
|
388
|
-
param={"singermid": mid, "order":
|
|
483
|
+
param={"singermid": mid, "order": order, "count": num, "start": (page - 1) * num},
|
|
389
484
|
pager_strategy=OffsetStrategy[SingerMvListResponse](
|
|
390
485
|
offset_key="start",
|
|
391
486
|
page_size_key="count",
|
|
@@ -82,8 +82,20 @@ async def test_get_tab_detail_song(client: Client) -> None:
|
|
|
82
82
|
page=1,
|
|
83
83
|
num=10,
|
|
84
84
|
)
|
|
85
|
-
assert result.song_tab
|
|
86
|
-
|
|
85
|
+
assert result.song_tab.songs
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
async def test_get_tab_detail_song_with_order(client: Client) -> None:
|
|
89
|
+
"""测试使用排序参数获取歌手歌曲 Tab 模型."""
|
|
90
|
+
result = await client.singer.get_tab_detail(
|
|
91
|
+
mid="0025NhlN2yWrP4",
|
|
92
|
+
tab_type=TabType.SONG,
|
|
93
|
+
page=1,
|
|
94
|
+
num=5,
|
|
95
|
+
order=1,
|
|
96
|
+
)
|
|
97
|
+
assert result.song_tab.songs
|
|
98
|
+
assert result.order == 1
|
|
87
99
|
|
|
88
100
|
|
|
89
101
|
async def test_get_tab_detail_album(client: Client) -> None:
|
|
@@ -94,8 +106,21 @@ async def test_get_tab_detail_album(client: Client) -> None:
|
|
|
94
106
|
page=1,
|
|
95
107
|
num=10,
|
|
96
108
|
)
|
|
97
|
-
assert result.album_tab
|
|
98
|
-
assert result.album_tab
|
|
109
|
+
assert result.album_tab.albums
|
|
110
|
+
assert result.album_tab.type_list.default_id == 0
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
async def test_get_tab_detail_album_with_filter(client: Client) -> None:
|
|
114
|
+
"""测试携带分类筛选参数获取歌手专辑 Tab, 服务端返回筛选列表."""
|
|
115
|
+
result = await client.singer.get_tab_detail(
|
|
116
|
+
mid="000GGDys0yA0Nk",
|
|
117
|
+
tab_type=TabType.ALBUM,
|
|
118
|
+
page=1,
|
|
119
|
+
num=5,
|
|
120
|
+
extension={"IsNeedFilterType": 1, "FilterType": 2},
|
|
121
|
+
)
|
|
122
|
+
assert result.album_tab.type_list.items
|
|
123
|
+
assert {item.id for item in result.album_tab.type_list.items} == {0, 1, 2, 3, 4}
|
|
99
124
|
|
|
100
125
|
|
|
101
126
|
async def test_get_tab_detail_video(client: Client) -> None:
|
|
@@ -106,8 +131,19 @@ async def test_get_tab_detail_video(client: Client) -> None:
|
|
|
106
131
|
page=1,
|
|
107
132
|
num=10,
|
|
108
133
|
)
|
|
109
|
-
assert result.video_tab
|
|
110
|
-
|
|
134
|
+
assert result.video_tab.videos
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
async def test_get_tab_detail_video_with_tag(client: Client) -> None:
|
|
138
|
+
"""测试携带标签参数获取歌手视频 Tab, 服务端返回标签列表."""
|
|
139
|
+
result = await client.singer.get_tab_detail(
|
|
140
|
+
mid="000GGDys0yA0Nk",
|
|
141
|
+
tab_type=TabType.VIDEO,
|
|
142
|
+
page=1,
|
|
143
|
+
num=5,
|
|
144
|
+
extension={"TagID": 0, "IsNeedTagList": 1},
|
|
145
|
+
)
|
|
146
|
+
assert result.video_tab.tag_list
|
|
111
147
|
|
|
112
148
|
|
|
113
149
|
async def test_get_desc(client: Client) -> None:
|
|
@@ -149,6 +185,7 @@ async def test_get_songs_list_with_params(client: Client) -> None:
|
|
|
149
185
|
mid="0025NhlN2yWrP4",
|
|
150
186
|
num=10,
|
|
151
187
|
page=2,
|
|
188
|
+
order=1,
|
|
152
189
|
)
|
|
153
190
|
assert result.song_list
|
|
154
191
|
assert len(result.song_list) <= result.total_num
|
|
@@ -167,6 +204,7 @@ async def test_get_album_list_with_params(client: Client) -> None:
|
|
|
167
204
|
mid="0025NhlN2yWrP4",
|
|
168
205
|
num=10,
|
|
169
206
|
page=2,
|
|
207
|
+
order=1,
|
|
170
208
|
)
|
|
171
209
|
assert result.album_list
|
|
172
210
|
|
|
@@ -35,7 +35,7 @@ from qqmusic_api.models.songlist import GetSonglistDetailResponse
|
|
|
35
35
|
from qqmusic_api.models.top import TopDetailResponse
|
|
36
36
|
from qqmusic_api.models.user import DislikeListData, RelationUser, UserRelationListResponse
|
|
37
37
|
from qqmusic_api.modules.search import SearchType
|
|
38
|
-
from qqmusic_api.modules.singer import TabType
|
|
38
|
+
from qqmusic_api.modules.singer import OrderType, TabType
|
|
39
39
|
from qqmusic_api.modules.song import SongFileInfo
|
|
40
40
|
|
|
41
41
|
pytestmark = pytest.mark.core
|
|
@@ -105,11 +105,15 @@ def test_client_facade_pure_paginated_types():
|
|
|
105
105
|
tab_req = client.singer.get_tab_detail("001BLpXF2DyJe2", TabType.SONG)
|
|
106
106
|
assert_type(tab_req, PaginatedCgiRequest[HomepageTabDetailResponse])
|
|
107
107
|
|
|
108
|
+
tab_song_req = client.singer.get_tab_detail("001BLpXF2DyJe2", TabType.SONG, order=OrderType.HOT)
|
|
109
|
+
assert_type(tab_song_req, PaginatedCgiRequest[HomepageTabDetailResponse])
|
|
110
|
+
|
|
111
|
+
tab_album_req = client.singer.get_tab_detail("001BLpXF2DyJe2", TabType.ALBUM, order=OrderType.LATEST)
|
|
112
|
+
assert_type(tab_album_req, PaginatedCgiRequest[HomepageTabDetailResponse])
|
|
108
113
|
tab_annotated: PaginatedCgiRequest[HomepageTabDetailResponse] = client.singer.get_tab_detail(
|
|
109
|
-
"001BLpXF2DyJe2", TabType.SONG
|
|
114
|
+
"001BLpXF2DyJe2", TabType.SONG, order=0
|
|
110
115
|
)
|
|
111
116
|
assert_type(tab_annotated, PaginatedCgiRequest[HomepageTabDetailResponse])
|
|
112
|
-
|
|
113
117
|
general_req = client.search.general_search("周杰伦")
|
|
114
118
|
assert_type(general_req, PaginatedCgiRequest[GeneralSearchResponse])
|
|
115
119
|
|