aioqzone 1.9.2.dev2__tar.gz → 1.9.3.dev1__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.
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/PKG-INFO +2 -2
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/pyproject.toml +2 -2
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/api/h5/model.py +21 -7
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/api/__init__.py +10 -1
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/api/request.py +6 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/api/response.py +13 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/LICENSE +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/README.md +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/api/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/api/h5/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/api/login/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/api/login/_base.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/exception.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/message.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/api/feed.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/api/profile.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/protocol/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/protocol/config.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/model/protocol/entity.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/utils/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/utils/entity.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/utils/regex.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/utils/retry.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/aioqzone/utils/time.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/base.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/constant.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/exception.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/message.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/py.typed +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/qr/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/qr/type.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/type.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/_model.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/_model.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/capsess.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/click/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/click/_types.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/pil_utils.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/select/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/select/_types.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/slide/__init__.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/captcha/slide/_types.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/encrypt.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/h5.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/up/web.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/utils/encrypt.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/utils/iter.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/utils/jsjson.py +0 -0
- {aioqzone-1.9.2.dev2 → aioqzone-1.9.3.dev1}/src/qqqr/utils/net.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: aioqzone
|
|
3
|
-
Version: 1.9.
|
|
3
|
+
Version: 1.9.3.dev1
|
|
4
4
|
Summary: A Python wrapper for Qzone login and H5 APIs.
|
|
5
5
|
License: AGPL-3.0
|
|
6
6
|
Keywords: qzone-api,autologin,asyncio-spider
|
|
@@ -22,7 +22,7 @@ Provides-Extra: slide-captcha
|
|
|
22
22
|
Requires-Dist: aiohttp (>=3.9.0,<4.0.0)
|
|
23
23
|
Requires-Dist: exceptiongroup (>=1.1.1,<2.0.0)
|
|
24
24
|
Requires-Dist: pillow (>=10.1.0,<11.0.0)
|
|
25
|
-
Requires-Dist: pychaosvm (>=0.4.
|
|
25
|
+
Requires-Dist: pychaosvm (>=0.4.3,<0.5.0)
|
|
26
26
|
Requires-Dist: pydantic (>=2.5.0,<3.0.0)
|
|
27
27
|
Requires-Dist: pydantic-settings (>=2.2.0,<3.0.0)
|
|
28
28
|
Requires-Dist: rsa (>=4.8,<5.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "aioqzone"
|
|
3
|
-
version = "1.9.
|
|
3
|
+
version = "1.9.3.dev1"
|
|
4
4
|
description = "A Python wrapper for Qzone login and H5 APIs."
|
|
5
5
|
authors = ["aioqzone <22952836+JamzumSum@users.noreply.github.com>"]
|
|
6
6
|
license = "AGPL-3.0"
|
|
@@ -36,7 +36,7 @@ tenacity = ">=8.2.3,<10.0.0"
|
|
|
36
36
|
exceptiongroup = "^1.1.1"
|
|
37
37
|
tylisten = "^2.1.4"
|
|
38
38
|
pillow = "^10.1.0"
|
|
39
|
-
pychaosvm = { version = "~0.4.
|
|
39
|
+
pychaosvm = { version = "~0.4.3", source = "aioqzone-index" }
|
|
40
40
|
slide-tc = {version = "~0.1.1", optional = true, source = "aioqzone-index" }
|
|
41
41
|
|
|
42
42
|
[tool.poetry.extras]
|
|
@@ -61,13 +61,15 @@ class QzoneH5API:
|
|
|
61
61
|
|
|
62
62
|
async for attempt in self._relogin_retry:
|
|
63
63
|
with attempt:
|
|
64
|
-
if
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
params
|
|
64
|
+
if api.login_required:
|
|
65
|
+
if (gtk := self.login.gtk) == 0:
|
|
66
|
+
raise TryAgain("no login state")
|
|
67
|
+
|
|
68
|
+
if api.attach_token:
|
|
69
|
+
params["g_tk"] = gtk
|
|
70
|
+
hostuin: int = getattr(api.params, "hostuin", self.login.uin)
|
|
71
|
+
if qzonetoken := self.qzone_tokens.get(hostuin):
|
|
72
|
+
params["qzonetoken"] = qzonetoken
|
|
71
73
|
|
|
72
74
|
async with self.client.request(
|
|
73
75
|
api.http_method,
|
|
@@ -252,3 +254,15 @@ class QzoneH5API:
|
|
|
252
254
|
response=DeleteUgcResp,
|
|
253
255
|
)
|
|
254
256
|
)
|
|
257
|
+
|
|
258
|
+
async def avatar(self, hostuin: int, size: t.Literal[100, 640]) -> AvatarResponse:
|
|
259
|
+
"""Get avatar from uin. Do not require login.
|
|
260
|
+
|
|
261
|
+
:param hostuin: the uin whose avatar to be get
|
|
262
|
+
:param size: availible sizes: `100`|`640`
|
|
263
|
+
"""
|
|
264
|
+
return await self.call(
|
|
265
|
+
AvatarApi(
|
|
266
|
+
params=AvatarParams.model_validate(locals()),
|
|
267
|
+
),
|
|
268
|
+
)
|
|
@@ -23,12 +23,13 @@ class QzoneApi(BaseModel, t.Generic[TyRequest, TyResponse]):
|
|
|
23
23
|
referer: str = "https://h5.qzone.qq.com/"
|
|
24
24
|
|
|
25
25
|
attach_token: t.ClassVar[bool] = True
|
|
26
|
+
login_required: t.ClassVar[bool] = True
|
|
26
27
|
params: TyRequest = Field(default_factory=QzoneRequestParams)
|
|
27
28
|
response: t.ClassVar[t.Type[TyResponse]] # type: ignore
|
|
28
29
|
|
|
29
30
|
@property
|
|
30
31
|
def url(self) -> URL:
|
|
31
|
-
return URL(str(self.host)).with_path(self.path)
|
|
32
|
+
return URL(str(self.host)).with_path(self.path.format(**self.params.model_dump()))
|
|
32
33
|
|
|
33
34
|
|
|
34
35
|
class IndexPageApi(QzoneApi[QzoneRequestParams, IndexPageResp]):
|
|
@@ -124,3 +125,11 @@ class PhotosPreuploadApi(QzoneApi[PhotosPreuploadParams, PhotosPreuploadResponse
|
|
|
124
125
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
125
126
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
126
127
|
path: t.ClassVar[str] = "/up/cgi-bin/upload/cgi_upload_pic_v2"
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
class AvatarApi(QzoneApi[AvatarParams, AvatarResponse]):
|
|
131
|
+
response: t.ClassVar = AvatarResponse
|
|
132
|
+
login_required: t.ClassVar[bool] = False
|
|
133
|
+
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
134
|
+
host: t.ClassVar[str] = "https://qlogo2.store.qq.com"
|
|
135
|
+
path: t.ClassVar[str] = "/qzone/{hostuin}/{hostuin}/{size}"
|
|
@@ -16,6 +16,7 @@ from .response import PicInfo, UploadPicResponse
|
|
|
16
16
|
__all__ = [
|
|
17
17
|
"QzoneRequestParams",
|
|
18
18
|
"ActiveFeedsParams",
|
|
19
|
+
"AvatarParams",
|
|
19
20
|
"GetFeedsParams",
|
|
20
21
|
"ProfileParams",
|
|
21
22
|
"ShuoshuoParams",
|
|
@@ -241,3 +242,8 @@ class PhotosPreuploadParams(QzoneRequestParams):
|
|
|
241
242
|
|
|
242
243
|
params.update(md5="|".join(md5), filelen="|".join(size))
|
|
243
244
|
return params
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
class AvatarParams(QzoneRequestParams):
|
|
248
|
+
hostuin: int
|
|
249
|
+
size: t.Literal[100, 640] = 100
|
|
@@ -44,6 +44,7 @@ __all__ = [
|
|
|
44
44
|
"FeedData",
|
|
45
45
|
"PicInfo",
|
|
46
46
|
"ProfileFeedData",
|
|
47
|
+
"AvatarResponse",
|
|
47
48
|
]
|
|
48
49
|
|
|
49
50
|
validate_strdict = TypeAdapter(StrDict).validate_python
|
|
@@ -288,3 +289,15 @@ class PhotosPreuploadResponse(QzoneResponse):
|
|
|
288
289
|
picinfos = json_loads(m.group(1))
|
|
289
290
|
assert isinstance(picinfos, list)
|
|
290
291
|
return dict(photos=[PicInfo.from_response_object(info["picinfo"]) for info in picinfos]) # type: ignore
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
class AvatarResponse(QzoneResponse):
|
|
295
|
+
_errno_key = None
|
|
296
|
+
_msg_key = None
|
|
297
|
+
_data_key = None
|
|
298
|
+
|
|
299
|
+
avatar: bytes
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
async def response_to_object(cls, response: ClientResponse) -> "StrDict":
|
|
303
|
+
return {"avatar": await response.content.read()}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|