qqmusic-api-python 0.5.3__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/.dockerignore +26 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.gitignore +0 -1
- qqmusic_api_python-0.6.1/CLAUDE.md +1 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/PKG-INFO +4 -5
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/coding.md +15 -54
- qqmusic_api_python-0.6.1/docs/reference/core/exception.md +3 -0
- qqmusic_api_python-0.6.1/docs/reference/modules/private_message.md +3 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/release-notes.md +45 -0
- qqmusic_api_python-0.6.1/docs/tutorial/client.md +96 -0
- qqmusic_api_python-0.6.1/docs/tutorial/web.md +79 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/examples/phone_login.py +1 -1
- qqmusic_api_python-0.6.1/examples/private_message.py +74 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/examples/qrcode_login.py +1 -1
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/pyproject.toml +18 -19
- qqmusic_api_python-0.6.1/qqmusic_api/__init__.py +40 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/algorithms/__init__.py +0 -2
- qqmusic_api_python-0.6.1/qqmusic_api/core/__init__.py +40 -0
- qqmusic_api_python-0.6.1/qqmusic_api/core/client.py +556 -0
- qqmusic_api_python-0.6.1/qqmusic_api/core/exceptions.py +136 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/core/pagination.py +5 -2
- qqmusic_api_python-0.6.1/qqmusic_api/core/request.py +142 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/core/versioning.py +2 -14
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/comment.py +20 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/login.py +5 -4
- qqmusic_api_python-0.6.1/qqmusic_api/models/private_message.py +350 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/request.py +2 -1
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/song.py +1 -3
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/__init__.py +2 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/_base.py +17 -64
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/album.py +6 -6
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/comment.py +60 -1
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/login.py +204 -316
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/login_utils.py +8 -12
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/lyric.py +3 -3
- qqmusic_api_python-0.6.1/qqmusic_api/modules/private_message.py +518 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/search.py +2 -2
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/song.py +24 -9
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/songlist.py +3 -4
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/__init__.py +2 -2
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/common.py +26 -13
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/device.py +60 -57
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/qimei.py +82 -56
- qqmusic_api_python-0.6.1/tests/conftest.py +125 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_login.py +30 -21
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_login_utils.py +43 -4
- qqmusic_api_python-0.6.1/tests/test_private_message.py +38 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_search.py +17 -4
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_songlist.py +13 -7
- qqmusic_api_python-0.6.1/uv.lock +2062 -0
- qqmusic_api_python-0.6.1/web/.gitignore +5 -0
- qqmusic_api_python-0.6.1/web/Dockerfile +20 -0
- qqmusic_api_python-0.6.1/web/README.md +101 -0
- qqmusic_api_python-0.6.1/web/accounts.example.toml +40 -0
- qqmusic_api_python-0.6.1/web/config.example.toml +96 -0
- qqmusic_api_python-0.6.1/web/docker-compose.yml +14 -0
- qqmusic_api_python-0.6.1/web/run.py +95 -0
- qqmusic_api_python-0.6.1/web/src/app.py +263 -0
- qqmusic_api_python-0.6.1/web/src/core/__init__.py +1 -0
- qqmusic_api_python-0.6.1/web/src/core/auth.py +212 -0
- qqmusic_api_python-0.6.1/web/src/core/cache.py +153 -0
- qqmusic_api_python-0.6.1/web/src/core/config.py +210 -0
- qqmusic_api_python-0.6.1/web/src/core/credential_store.py +234 -0
- qqmusic_api_python-0.6.1/web/src/core/deps.py +66 -0
- qqmusic_api_python-0.6.1/web/src/core/response.py +40 -0
- qqmusic_api_python-0.6.1/web/src/core/security.py +286 -0
- qqmusic_api_python-0.6.1/web/src/modules/__init__.py +1 -0
- qqmusic_api_python-0.6.1/web/src/modules/login.py +218 -0
- qqmusic_api_python-0.6.1/web/src/modules/mv.py +13 -0
- qqmusic_api_python-0.6.1/web/src/modules/singer.py +8 -0
- qqmusic_api_python-0.6.1/web/src/modules/song.py +165 -0
- qqmusic_api_python-0.6.1/web/src/modules/songlist.py +33 -0
- qqmusic_api_python-0.6.1/web/src/routes/__init__.py +32 -0
- qqmusic_api_python-0.6.1/web/src/routes/_helpers.py +137 -0
- qqmusic_api_python-0.6.1/web/src/routes/album.py +18 -0
- qqmusic_api_python-0.6.1/web/src/routes/comment.py +49 -0
- qqmusic_api_python-0.6.1/web/src/routes/login.py +80 -0
- qqmusic_api_python-0.6.1/web/src/routes/lyric.py +10 -0
- qqmusic_api_python-0.6.1/web/src/routes/mv.py +34 -0
- qqmusic_api_python-0.6.1/web/src/routes/recommend.py +39 -0
- qqmusic_api_python-0.6.1/web/src/routes/search.py +40 -0
- qqmusic_api_python-0.6.1/web/src/routes/singer.py +95 -0
- qqmusic_api_python-0.6.1/web/src/routes/song.py +122 -0
- qqmusic_api_python-0.6.1/web/src/routes/songlist.py +63 -0
- qqmusic_api_python-0.6.1/web/src/routes/top.py +18 -0
- qqmusic_api_python-0.6.1/web/src/routes/user.py +109 -0
- qqmusic_api_python-0.6.1/web/src/routing/__init__.py +1 -0
- qqmusic_api_python-0.6.1/web/src/routing/docstrings.py +164 -0
- qqmusic_api_python-0.6.1/web/src/routing/executor.py +153 -0
- qqmusic_api_python-0.6.1/web/src/routing/params.py +259 -0
- qqmusic_api_python-0.6.1/web/src/routing/route_types.py +174 -0
- qqmusic_api_python-0.6.1/web/src/routing/router_factory.py +392 -0
- qqmusic_api_python-0.6.1/web/tests/test_web_docstrings.py +55 -0
- qqmusic_api_python-0.6.1/web/tests/test_web_enums.py +113 -0
- qqmusic_api_python-0.6.1/web/tests/test_web_route_validation.py +85 -0
- qqmusic_api_python-0.6.1/web/tests/test_web_routes.py +155 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/zensical.toml +2 -0
- qqmusic_api_python-0.5.3/docs/reference/core/exception.md +0 -21
- qqmusic_api_python-0.5.3/docs/tutorial/client.md +0 -68
- qqmusic_api_python-0.5.3/qqmusic_api/__init__.py +0 -52
- qqmusic_api_python-0.5.3/qqmusic_api/algorithms/sign.py +0 -58
- qqmusic_api_python-0.5.3/qqmusic_api/core/__init__.py +0 -67
- qqmusic_api_python-0.5.3/qqmusic_api/core/client.py +0 -807
- qqmusic_api_python-0.5.3/qqmusic_api/core/exceptions.py +0 -365
- qqmusic_api_python-0.5.3/qqmusic_api/core/request.py +0 -402
- qqmusic_api_python-0.5.3/tests/conftest.py +0 -96
- qqmusic_api_python-0.5.3/uv.lock +0 -1502
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.agents/skills/pydantic/SKILL.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.agents/skills/python-standards/SKILL.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.agents/skills/tarsio/SKILL.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.agents/skills/tarsio/references/api-reference.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.agents/skills/uv-package-manager/SKILL.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/bug.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/ISSUE_TEMPLATE/feature.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/renovate.json +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/workflows/checking.yaml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/workflows/docs.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/workflows/release.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.github/workflows/testing.yml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/.markdownlint-cli2.yaml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/AGENTS.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/LICENSE +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/README.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/assets/qq-music.svg +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/cliff.toml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/contributing.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/index.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/core/client.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/core/pagination.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/core/request.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/core/versioning.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/album.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/base.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/comment.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/login.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/lyric.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/mv.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/recommend.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/request.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/search.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/singer.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/song.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/songlist.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/top.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/model/user.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/album.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/comment.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/login.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/login_utils.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/lyric.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/mv.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/recommend.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/search.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/singer.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/song.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/songlist.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/top.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/reference/modules/user.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/tutorial/credential.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/tutorial/pagination.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/docs/tutorial/start.md +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/examples/download_song.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/prek.toml +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/algorithms/tripledes.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/__init__.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/album.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/base.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/lyric.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/mv.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/recommend.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/search.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/singer.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/songlist.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/top.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/models/user.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/mv.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/recommend.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/singer.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/top.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/modules/user.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/qqmusic_api/utils/mqtt.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/scripts/ag-1.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_album.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_comment.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_lyric.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_mv.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_recommend.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_singer.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_song.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_top.py +0 -0
- {qqmusic_api_python-0.5.3 → qqmusic_api_python-0.6.1}/tests/test_user.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
__pycache__
|
|
2
|
+
*.pyc
|
|
3
|
+
*.pyo
|
|
4
|
+
.venv
|
|
5
|
+
.conda
|
|
6
|
+
.git
|
|
7
|
+
.gitignore
|
|
8
|
+
.gitattributes
|
|
9
|
+
.github
|
|
10
|
+
.claude
|
|
11
|
+
docs
|
|
12
|
+
tests
|
|
13
|
+
web/tests
|
|
14
|
+
*.md
|
|
15
|
+
!README.md
|
|
16
|
+
.DS_Store
|
|
17
|
+
*.egg-info
|
|
18
|
+
dist
|
|
19
|
+
.ruff_cache
|
|
20
|
+
.mypy_cache
|
|
21
|
+
.pytest_cache
|
|
22
|
+
.prek_cache
|
|
23
|
+
*.toml
|
|
24
|
+
!pyproject.toml
|
|
25
|
+
!web/config.toml
|
|
26
|
+
!web/accounts.toml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
AGENTS.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qqmusic-api-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: QQ音乐API封装库
|
|
5
5
|
Project-URL: documentation, https://l-1124.github.io/QQMusicApi/
|
|
6
6
|
Project-URL: homepage, https://l-1124.github.io/QQMusicApi/
|
|
@@ -29,13 +29,12 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
29
29
|
Classifier: Typing :: Typed
|
|
30
30
|
Requires-Python: >=3.10
|
|
31
31
|
Requires-Dist: anyio>=4.12.1
|
|
32
|
-
Requires-Dist: cryptography>=
|
|
33
|
-
Requires-Dist: httpx-retries>=0.4.6
|
|
34
|
-
Requires-Dist: httpx[http2]>=0.27.0
|
|
32
|
+
Requires-Dist: cryptography>=47.0.0
|
|
35
33
|
Requires-Dist: jsonpath-ng>=1.8.0
|
|
34
|
+
Requires-Dist: niquests[speedups]>=3.18.7
|
|
36
35
|
Requires-Dist: orjson>=3.10.15
|
|
37
36
|
Requires-Dist: paho-mqtt>=2.1.0
|
|
38
|
-
Requires-Dist: pydantic>=2.
|
|
37
|
+
Requires-Dist: pydantic>=2.13.3
|
|
39
38
|
Requires-Dist: tarsio>=0.5.1
|
|
40
39
|
Requires-Dist: typing-extensions>=4.12.2
|
|
41
40
|
Description-Content-Type: text/markdown
|
|
@@ -2,9 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
`qqmusic_api` 采用 `Client + ApiModule + Request` 的结构:
|
|
4
4
|
|
|
5
|
-
* `Client`
|
|
5
|
+
* `Client` 负责网络发送、平台信息和凭证。
|
|
6
6
|
* `ApiModule` 负责声明接口参数,并返回可 `await` 的 `Request`。
|
|
7
|
-
* `RequestGroup` 用于批量执行多个 `Request`。
|
|
8
7
|
|
|
9
8
|
## 调用流程图
|
|
10
9
|
|
|
@@ -16,31 +15,28 @@
|
|
|
16
15
|
-> Request
|
|
17
16
|
-> await request
|
|
18
17
|
-> Client.execute(request)
|
|
19
|
-
-> 根据 request.is_jce
|
|
20
|
-
-> Client.request_jce(...)
|
|
21
|
-
-> 或 Client.request_musicu(...)
|
|
18
|
+
-> Client.request_api(...) (根据 request.is_jce 分发改用 JCE 或 JSON 协议)
|
|
22
19
|
-> Client._build_result(...)
|
|
23
20
|
-> 返回原始 dict / TarsDict 或 Pydantic 模型
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
###
|
|
23
|
+
### 批量并发请求
|
|
27
24
|
|
|
28
25
|
```text
|
|
29
26
|
多个模块方法
|
|
30
|
-
->
|
|
31
|
-
->
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
字段包括 index / success / data / error
|
|
40
|
-
-> execute():
|
|
41
|
-
返回按添加顺序回填的 list[Any | Exception]
|
|
27
|
+
-> self._build_request(...)
|
|
28
|
+
-> Request 列表
|
|
29
|
+
-> Client.gather(requests)
|
|
30
|
+
-> 按协议、平台、公共参数和凭证分组
|
|
31
|
+
-> 每组按 batch_size 拆分为批量请求
|
|
32
|
+
-> 依次调用 Client.request_api(..., lazy=True) 生成响应任务
|
|
33
|
+
-> 使用客户端内部的 multiplexed AsyncSession 并发执行这些任务(self._session.gather)
|
|
34
|
+
-> 按 req_n 解析每个响应项
|
|
35
|
+
-> 按输入顺序返回结果
|
|
42
36
|
```
|
|
43
37
|
|
|
38
|
+
`gather` 的分组边界由 `Request._group_key` 决定。只有协议类型、显式平台、公共参数和凭证相同的请求才会合并到同一个批量请求中。
|
|
39
|
+
|
|
44
40
|
## 编写新的 API
|
|
45
41
|
|
|
46
42
|
API 按功能拆分在 `qqmusic_api/modules/` 下,添加新的 API 只需在对应的模块中添加请求方法即可。
|
|
@@ -76,7 +72,7 @@ class SearchApi(ApiModule):
|
|
|
76
72
|
Returns:
|
|
77
73
|
dict[str, Any]: 搜索结果字典.
|
|
78
74
|
"""
|
|
79
|
-
resp = await self._client.
|
|
75
|
+
resp = await self._client.request(
|
|
80
76
|
"GET",
|
|
81
77
|
"https://c.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg",
|
|
82
78
|
params={"key": keyword},
|
|
@@ -344,38 +340,3 @@ class Client:
|
|
|
344
340
|
|
|
345
341
|
return MyApi(self)
|
|
346
342
|
```
|
|
347
|
-
|
|
348
|
-
## 批量请求 `RequestGroup`
|
|
349
|
-
|
|
350
|
-
使用 `Client.request_group()` 可以批量提交请求。`RequestGroup` 会自动按 `platform`、`credential`、`comm` 和 `is_jce` 分组,并按 `batch_size` 分批发送。
|
|
351
|
-
|
|
352
|
-
`execute()` 会返回与添加顺序一致的完整结果列表:
|
|
353
|
-
|
|
354
|
-
```python
|
|
355
|
-
from qqmusic_api import Client
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
async def batch_query(song_ids: list[int]):
|
|
359
|
-
async with Client() as client:
|
|
360
|
-
group = client.request_group()
|
|
361
|
-
for song_id in song_ids:
|
|
362
|
-
group.add(client.song.get_detail(song_id))
|
|
363
|
-
|
|
364
|
-
return await group.execute()
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
`execute_iter()` 会按完成顺序流式返回 [`RequestGroupResult`][core.request.RequestGroupResult],不保证与添加顺序一致:
|
|
368
|
-
|
|
369
|
-
```python
|
|
370
|
-
from qqmusic_api import Client
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
async def batch_query_stream(song_ids: list[int]):
|
|
374
|
-
async with Client() as client:
|
|
375
|
-
group = client.request_group(batch_size=1, max_inflight_batches=4)
|
|
376
|
-
for song_id in song_ids:
|
|
377
|
-
group.add(client.song.get_detail(song_id))
|
|
378
|
-
|
|
379
|
-
async for result in group.execute_iter():
|
|
380
|
-
print(result.index, result.module, result.method, result.success)
|
|
381
|
-
```
|
|
@@ -1,4 +1,49 @@
|
|
|
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
|
+
|
|
27
|
+
## [[0.5.3](https://github.com/L-1124/QQMusicApi/compare/v0.5.2..v0.5.3)] - 2026-05-01
|
|
28
|
+
|
|
29
|
+
### Bug 修复
|
|
30
|
+
|
|
31
|
+
* **(song)** 传递歌曲链接请求凭证 ([8667e8c](https://github.com/L-1124/QQMusicApi/commit/8667e8c16a071d5b2e96e91e90441db724d71169)) by [@L-1124](https://github.com/L-1124)
|
|
32
|
+
* 模型字段类型出现`int | str` ([ed2e450](https://github.com/L-1124/QQMusicApi/commit/ed2e4503fab162ebdabae7368ffd408584f1e91a)) by [@L-1124](https://github.com/L-1124)
|
|
33
|
+
* 手机登录没有正常返回验证链接 ([3f69c5d](https://github.com/L-1124/QQMusicApi/commit/3f69c5d3f51353c73ab1c9f5a6637e29dc0aebe4)) by [@L-1124](https://github.com/L-1124)
|
|
34
|
+
* [**breaking**] 拼写错误及其他问题 ([6bd129e](https://github.com/L-1124/QQMusicApi/commit/6bd129eed7d9d8bd1b76fbd6389840ee295d6802)) by [@Copilot](https://github.com/Copilot) in [#242](https://github.com/L-1124/QQMusicApi/pull/242)
|
|
35
|
+
|
|
36
|
+
### 功能更新
|
|
37
|
+
|
|
38
|
+
* **(api)** 统一分页参数,暴露搜索一致性参数 ([a3d3a5d](https://github.com/L-1124/QQMusicApi/commit/a3d3a5d36b0b1ee85628d4bafde17551ae76e5fe)) by [@L-1124](https://github.com/L-1124)
|
|
39
|
+
* **(login)** 细化登录异常体系并修正请求参数 ([fb9d2e6](https://github.com/L-1124/QQMusicApi/commit/fb9d2e6ed180b7188cc059b3a98ce67ec4760c0d)) by [@L-1124](https://github.com/L-1124) in [#245](https://github.com/L-1124/QQMusicApi/pull/245)
|
|
40
|
+
|
|
41
|
+
### 贡献者
|
|
42
|
+
|
|
43
|
+
* @L-1124
|
|
44
|
+
* @Copilot [#242](https://github.com/L-1124/QQMusicApi/pull/242)
|
|
45
|
+
* @github-actions[bot]
|
|
46
|
+
|
|
2
47
|
## [[0.5.2](https://github.com/L-1124/QQMusicApi/compare/v0.5.1..v0.5.2)] - 2026-04-18
|
|
3
48
|
|
|
4
49
|
### Bug 修复
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Client
|
|
2
|
+
|
|
3
|
+
`Client` 用于统一管理连接、凭证、设备信息与请求配置,是调用 API 的入口。
|
|
4
|
+
|
|
5
|
+
## 用法
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
import asyncio
|
|
9
|
+
|
|
10
|
+
from qqmusic_api import Client
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def main() -> None:
|
|
14
|
+
async with Client() as client:
|
|
15
|
+
result = await client.search.quick_search("周杰伦")
|
|
16
|
+
print(result)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
asyncio.run(main())
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## 批量并发请求
|
|
23
|
+
|
|
24
|
+
`Client.gather()` 可以一次执行多个 `Request`,并按传入顺序返回解析后的结果。适合同时请求多个互不依赖的 API。
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import asyncio
|
|
28
|
+
|
|
29
|
+
from qqmusic_api import Client
|
|
30
|
+
from qqmusic_api.modules.search import SearchType
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
async def main() -> None:
|
|
34
|
+
async with Client() as client:
|
|
35
|
+
results = await client.gather(
|
|
36
|
+
[
|
|
37
|
+
client.search.search_by_type("周杰伦", SearchType.SONG, num=1),
|
|
38
|
+
client.search.search_by_type("林俊杰", SearchType.SONG, num=1),
|
|
39
|
+
]
|
|
40
|
+
)
|
|
41
|
+
print(results[0].song)
|
|
42
|
+
print(results[1].song)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
asyncio.run(main())
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`gather()` 的返回值顺序始终与传入的请求顺序一致。
|
|
49
|
+
|
|
50
|
+
如果希望单个请求失败时不立即抛出异常,可以启用 `return_exceptions`:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
results = await client.gather(
|
|
54
|
+
[
|
|
55
|
+
client.search.search_by_type("周杰伦", SearchType.SONG, num=1),
|
|
56
|
+
client.search.search_by_type("林俊杰", SearchType.SONG, num=1),
|
|
57
|
+
],
|
|
58
|
+
return_exceptions=True,
|
|
59
|
+
)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
此时失败项会以异常对象的形式出现在对应位置,成功项仍返回正常的响应模型。
|
|
63
|
+
|
|
64
|
+
## 全局凭证
|
|
65
|
+
|
|
66
|
+
如果你的场景需要登录,可以在初始化 `Client` 时直接注入 `Credential`:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from qqmusic_api import Client, Credential
|
|
70
|
+
|
|
71
|
+
credential = Credential(musicid=123456, musickey="Q_H_L_xxx")
|
|
72
|
+
client = Client(credential=credential)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 请求平台
|
|
76
|
+
|
|
77
|
+
默认的请求平台是 `android`,如果需要可以在初始化时覆盖:
|
|
78
|
+
|
|
79
|
+
!!! note
|
|
80
|
+
|
|
81
|
+
部分 API 的请求平台是固定的,无法覆盖。
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
import asyncio
|
|
85
|
+
|
|
86
|
+
from qqmusic_api import Client, Platform
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
async def main():
|
|
90
|
+
async with Client(platform=Platform.DESKTOP) as client:
|
|
91
|
+
...
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
asyncio.run(_main())
|
|
95
|
+
|
|
96
|
+
```
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Web 服务
|
|
2
|
+
|
|
3
|
+
Web 服务将 QQMusicApi 暴露为 HTTP API。
|
|
4
|
+
|
|
5
|
+
## 1. 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
git clone https://github.com/luren-dc/QQMusicApi
|
|
9
|
+
cd QQMusicApi
|
|
10
|
+
uv sync --group web
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
可使用环境变量或者编辑`web/config.toml` 来配置服务参数
|
|
14
|
+
|
|
15
|
+
## 2. 启动服务
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv run python web/run.py
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 3. 查看 API 文档
|
|
22
|
+
|
|
23
|
+
打开 [http://localhost:8000/docs](http://localhost:8000/docs) 可以查看所有可用接口。
|
|
24
|
+
|
|
25
|
+
## 4. 认证方式
|
|
26
|
+
|
|
27
|
+
需要登录凭证的接口通过 **Cookie** 传递 QQ 音乐登录信息:
|
|
28
|
+
|
|
29
|
+
| Cookie 字段 | 说明 | 是否必须 |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| `musicid` | QQ 音乐用户 ID | ✅ 必须 |
|
|
32
|
+
| `musickey` | QQ 音乐密钥 | ✅ 必须 |
|
|
33
|
+
| `openid` | QQ 音乐 OpenID | 可选 |
|
|
34
|
+
| `refresh_token` | Refresh Token | 可选 |
|
|
35
|
+
| `access_token` | Access Token | 可选 |
|
|
36
|
+
| `expired_at` | 登录态过期时间戳 | 可选 |
|
|
37
|
+
| `unionid` | UnionID | 可选 |
|
|
38
|
+
| `str_musicid` | 字符串形式的用户 ID | 可选 |
|
|
39
|
+
| `refresh_key` | Refresh Key | 可选 |
|
|
40
|
+
|
|
41
|
+
`musicid` 与 `musickey` 必须同时提供;如果未携带任何 Cookie,接口将以未登录状态调用。
|
|
42
|
+
|
|
43
|
+
## 5. 响应格式
|
|
44
|
+
|
|
45
|
+
所有接口均返回统一的 JSON 结构:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"code": 0,
|
|
50
|
+
"msg": "ok",
|
|
51
|
+
"data": { ... }
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| 字段 | 说明 |
|
|
56
|
+
| --- | --- |
|
|
57
|
+
| `code` | 状态码。成功为 `0`,失败为 `-1`。 |
|
|
58
|
+
| `msg` | 面向调用方的状态说明。 |
|
|
59
|
+
| `data` | 业务数据,失败时可能包含错误详情。 |
|
|
60
|
+
|
|
61
|
+
## 6. 请求示例
|
|
62
|
+
|
|
63
|
+
### 搜索歌曲
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
curl "http://localhost:8000/search/search_by_type?keyword=周杰伦&search_type=song&num=5"
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 获取歌曲详情
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
curl "http://localhost:8000/song/123456/detail"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 获取歌词(需要歌曲 ID 或 MID)
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
curl "http://localhost:8000/song/123456/lyric?trans=true"
|
|
79
|
+
```
|
|
@@ -27,7 +27,7 @@ async def phone_login_example() -> None:
|
|
|
27
27
|
print("验证码已发送")
|
|
28
28
|
|
|
29
29
|
auth_code = (await asyncio.to_thread(input, "请输入验证码: ")).strip()
|
|
30
|
-
credential = await session.authorize(
|
|
30
|
+
credential = await session.authorize(auth_code)
|
|
31
31
|
print(f"登录成功! MusicID: {credential.musicid}")
|
|
32
32
|
|
|
33
33
|
except LoginError as e:
|
|
@@ -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())
|
|
@@ -23,7 +23,7 @@ def show_qrcode(qr: QR) -> None:
|
|
|
23
23
|
async def qrcode_login_example(login_type: QRLoginType) -> None:
|
|
24
24
|
"""二维码登录示例."""
|
|
25
25
|
try:
|
|
26
|
-
async with Client(
|
|
26
|
+
async with Client() as client:
|
|
27
27
|
print(f"正在获取 {login_type.name} 二维码...")
|
|
28
28
|
session = QRCodeLoginSession(
|
|
29
29
|
client.login,
|
|
@@ -33,13 +33,12 @@ classifiers = [
|
|
|
33
33
|
]
|
|
34
34
|
dependencies = [
|
|
35
35
|
"anyio>=4.12.1",
|
|
36
|
-
"cryptography>=
|
|
37
|
-
"httpx-retries>=0.4.6",
|
|
38
|
-
"httpx[http2]>=0.27.0",
|
|
36
|
+
"cryptography>=47.0.0",
|
|
39
37
|
"jsonpath-ng>=1.8.0",
|
|
38
|
+
"niquests[speedups]>=3.18.7",
|
|
40
39
|
"orjson>=3.10.15",
|
|
41
40
|
"paho-mqtt>=2.1.0",
|
|
42
|
-
"pydantic>=2.
|
|
41
|
+
"pydantic>=2.13.3",
|
|
43
42
|
"tarsio>=0.5.1",
|
|
44
43
|
"typing-extensions>=4.12.2",
|
|
45
44
|
]
|
|
@@ -72,9 +71,16 @@ linting = [
|
|
|
72
71
|
"ruff>=0.15.6",
|
|
73
72
|
]
|
|
74
73
|
testing = [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
"pytest>=9.0.2",
|
|
75
|
+
"pytest-asyncio>=1.3.0",
|
|
76
|
+
"pytest-sugar>=1.1.1",
|
|
77
|
+
]
|
|
78
|
+
web = [
|
|
79
|
+
"fastapi>=0.136.1",
|
|
80
|
+
"griffe>=2.0.2",
|
|
81
|
+
"pydantic-settings[toml]>=2.14.0",
|
|
82
|
+
"loguru>=0.7.3",
|
|
83
|
+
"uvicorn>=0.46.0",
|
|
78
84
|
]
|
|
79
85
|
|
|
80
86
|
[build-system]
|
|
@@ -93,6 +99,10 @@ path = "qqmusic_api/__init__.py"
|
|
|
93
99
|
[tool.pyrefly]
|
|
94
100
|
python-version = "3.10"
|
|
95
101
|
|
|
102
|
+
[tool.pyright]
|
|
103
|
+
venv = ".venv"
|
|
104
|
+
typeCheckingMode = "basic"
|
|
105
|
+
|
|
96
106
|
[tool.pytest]
|
|
97
107
|
addopts = ["-rxXs"]
|
|
98
108
|
pythonpath = ["."]
|
|
@@ -103,9 +113,6 @@ asyncio_mode = "auto"
|
|
|
103
113
|
line-length = 120
|
|
104
114
|
extend-exclude = ["docs"]
|
|
105
115
|
|
|
106
|
-
[tool.pyright]
|
|
107
|
-
typeCheckingMode = "basic"
|
|
108
|
-
|
|
109
116
|
[tool.ruff.lint]
|
|
110
117
|
extend-select = [
|
|
111
118
|
"A",
|
|
@@ -132,15 +139,7 @@ extend-select = [
|
|
|
132
139
|
"TRY",
|
|
133
140
|
"UP",
|
|
134
141
|
]
|
|
135
|
-
ignore = [
|
|
136
|
-
"TRY003",
|
|
137
|
-
"BLE001",
|
|
138
|
-
"TRY300",
|
|
139
|
-
"TRY301",
|
|
140
|
-
"TID252",
|
|
141
|
-
"C901",
|
|
142
|
-
"COM81"
|
|
143
|
-
]
|
|
142
|
+
ignore = ["TRY003", "BLE001", "TRY300", "TRY301", "TID252", "C901", "COM81"]
|
|
144
143
|
extend-per-file-ignores = { "qqmusic_api/core/exceptions.py" = ["D107"] }
|
|
145
144
|
pydocstyle = { convention = "google" }
|
|
146
145
|
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""QQMusic API 公开入口."""
|
|
2
|
+
|
|
3
|
+
from .core.client import Client
|
|
4
|
+
from .core.exceptions import (
|
|
5
|
+
ApiDataError,
|
|
6
|
+
ApiException,
|
|
7
|
+
BaseApiException,
|
|
8
|
+
CgiApiException,
|
|
9
|
+
CredentialExpiredError,
|
|
10
|
+
CredentialInvalidError,
|
|
11
|
+
CredentialRefreshError,
|
|
12
|
+
GlobalApiError,
|
|
13
|
+
HTTPError,
|
|
14
|
+
LoginError,
|
|
15
|
+
NetworkError,
|
|
16
|
+
RatelimitedError,
|
|
17
|
+
)
|
|
18
|
+
from .core.versioning import Platform
|
|
19
|
+
from .models.request import Credential
|
|
20
|
+
|
|
21
|
+
__version__ = "0.6.1"
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"ApiDataError",
|
|
25
|
+
"ApiException",
|
|
26
|
+
"BaseApiException",
|
|
27
|
+
"CgiApiException",
|
|
28
|
+
"Client",
|
|
29
|
+
"Credential",
|
|
30
|
+
"CredentialExpiredError",
|
|
31
|
+
"CredentialInvalidError",
|
|
32
|
+
"CredentialRefreshError",
|
|
33
|
+
"GlobalApiError",
|
|
34
|
+
"HTTPError",
|
|
35
|
+
"LoginError",
|
|
36
|
+
"NetworkError",
|
|
37
|
+
"Platform",
|
|
38
|
+
"RatelimitedError",
|
|
39
|
+
"__version__",
|
|
40
|
+
]
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import zlib
|
|
4
4
|
|
|
5
|
-
from .sign import sign_request
|
|
6
5
|
from .tripledes import DECRYPT, tripledes_crypt, tripledes_key_setup
|
|
7
6
|
|
|
8
7
|
_QRC_3DES_KEY = b"!@#)(*$%123ZXC!@!@#)(NHL"
|
|
@@ -44,5 +43,4 @@ def qrc_decrypt(encrypted_qrc: str | bytearray | bytes) -> str:
|
|
|
44
43
|
|
|
45
44
|
__all__ = [
|
|
46
45
|
"qrc_decrypt",
|
|
47
|
-
"sign_request",
|
|
48
46
|
]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"""core 模块."""
|
|
2
|
+
|
|
3
|
+
from .client import Client
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
ApiDataError,
|
|
6
|
+
ApiException,
|
|
7
|
+
BaseApiException,
|
|
8
|
+
CgiApiException,
|
|
9
|
+
CredentialExpiredError,
|
|
10
|
+
CredentialInvalidError,
|
|
11
|
+
CredentialRefreshError,
|
|
12
|
+
GlobalApiError,
|
|
13
|
+
HTTPError,
|
|
14
|
+
LoginError,
|
|
15
|
+
NetworkError,
|
|
16
|
+
RatelimitedError,
|
|
17
|
+
)
|
|
18
|
+
from .request import Request
|
|
19
|
+
from .versioning import DEFAULT_VERSION_POLICY, Platform, VersionPolicy, VersionProfile
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
"DEFAULT_VERSION_POLICY",
|
|
23
|
+
"ApiDataError",
|
|
24
|
+
"ApiException",
|
|
25
|
+
"BaseApiException",
|
|
26
|
+
"CgiApiException",
|
|
27
|
+
"Client",
|
|
28
|
+
"CredentialExpiredError",
|
|
29
|
+
"CredentialInvalidError",
|
|
30
|
+
"CredentialRefreshError",
|
|
31
|
+
"GlobalApiError",
|
|
32
|
+
"HTTPError",
|
|
33
|
+
"LoginError",
|
|
34
|
+
"NetworkError",
|
|
35
|
+
"Platform",
|
|
36
|
+
"RatelimitedError",
|
|
37
|
+
"Request",
|
|
38
|
+
"VersionPolicy",
|
|
39
|
+
"VersionProfile",
|
|
40
|
+
]
|