aioqzone 1.7.5.dev1__tar.gz → 1.8.1.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.7.5.dev1 → aioqzone-1.8.1.dev1}/PKG-INFO +4 -6
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/pyproject.toml +3 -5
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/api/h5/model.py +43 -86
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/api/__init__.py +30 -11
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/api/request.py +10 -4
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/api/response.py +3 -6
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/LICENSE +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/README.md +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/api/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/api/h5/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/api/login/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/api/login/_base.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/exception.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/message.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/api/feed.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/api/profile.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/protocol/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/protocol/config.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/model/protocol/entity.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/utils/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/utils/entity.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/utils/regex.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/utils/retry.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/aioqzone/utils/time.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/base.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/constant.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/exception.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/message.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/py.typed +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/qr/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/qr/type.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/type.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/_model.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/_model.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/capsess.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/pil_utils.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/select/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/select/_types.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/slide/__init__.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/captcha/slide/_types.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/encrypt.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/h5.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/up/web.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/utils/encrypt.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/utils/iter.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/utils/jsjson.py +0 -0
- {aioqzone-1.7.5.dev1 → aioqzone-1.8.1.dev1}/src/qqqr/utils/net.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: aioqzone
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.8.1.dev1
|
|
4
4
|
Summary: A Python wrapper for Qzone login and H5 APIs.
|
|
5
5
|
Home-page: https://github.com/aioqzone/aioqzone
|
|
6
6
|
License: AGPL-3.0
|
|
@@ -19,17 +19,15 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
20
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
21
|
Classifier: Typing :: Typed
|
|
22
|
-
Provides-Extra: captcha
|
|
22
|
+
Provides-Extra: slide-captcha
|
|
23
23
|
Requires-Dist: aiohttp (>=3.8.5,<4.0.0)
|
|
24
|
-
Requires-Dist: cssselect (>=1.1.0,<2.0.0)
|
|
25
24
|
Requires-Dist: exceptiongroup (>=1.1.1,<2.0.0)
|
|
26
|
-
Requires-Dist: lxml (>=4.9.1,<5.0.0)
|
|
27
25
|
Requires-Dist: pillow (>=10.0.1,<11.0.0)
|
|
28
|
-
Requires-Dist: pychaosvm (>=0.3.
|
|
26
|
+
Requires-Dist: pychaosvm (>=0.3.3,<0.4.0)
|
|
29
27
|
Requires-Dist: pydantic (>=2.0.3,<3.0.0)
|
|
30
28
|
Requires-Dist: pydantic-settings (>=2.0.2,<3.0.0)
|
|
31
29
|
Requires-Dist: rsa (>=4.8,<5.0)
|
|
32
|
-
Requires-Dist: slide-tc (>=0.1.1,<0.2.0) ; extra == "captcha"
|
|
30
|
+
Requires-Dist: slide-tc (>=0.1.1,<0.2.0) ; extra == "slide-captcha"
|
|
33
31
|
Requires-Dist: tenacity (>=8.2.3,<9.0.0)
|
|
34
32
|
Requires-Dist: tylisten (>=2.1.3,<3.0.0)
|
|
35
33
|
Project-URL: Bug Tracker, https://github.com/aioqzone/aioqzone/issues
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "aioqzone"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.8.1.dev1"
|
|
4
4
|
description = "A Python wrapper for Qzone login and H5 APIs."
|
|
5
5
|
authors = ["aioqzone <zzzzss990315@gmail.com>"]
|
|
6
6
|
license = "AGPL-3.0"
|
|
@@ -32,17 +32,15 @@ aiohttp = "^3.8.5"
|
|
|
32
32
|
pydantic = "^2.0.3"
|
|
33
33
|
pydantic-settings = "^2.0.2"
|
|
34
34
|
rsa = "^4.8"
|
|
35
|
-
lxml = "^4.9.1"
|
|
36
|
-
cssselect = "^1.1.0"
|
|
37
35
|
tenacity = "^8.2.3"
|
|
38
36
|
exceptiongroup = "^1.1.1"
|
|
39
37
|
tylisten = "^2.1.3"
|
|
40
38
|
pillow = "^10.0.1"
|
|
41
|
-
pychaosvm = { version = "~0.3.
|
|
39
|
+
pychaosvm = { version = "~0.3.3", source = "aioqzone-index" }
|
|
42
40
|
slide-tc = {version = "~0.1.1", optional = true, source = "aioqzone-index" }
|
|
43
41
|
|
|
44
42
|
[tool.poetry.extras]
|
|
45
|
-
captcha = ["slide-tc"]
|
|
43
|
+
slide-captcha = ["slide-tc"]
|
|
46
44
|
|
|
47
45
|
# dependency groups
|
|
48
46
|
[tool.poetry.group.test]
|
|
@@ -95,7 +95,7 @@ class QzoneH5API:
|
|
|
95
95
|
:raise `RuntimeError`: if any failure occurs in data parsing.
|
|
96
96
|
"""
|
|
97
97
|
|
|
98
|
-
r = await self.call(IndexPageApi(
|
|
98
|
+
r = await self.call(IndexPageApi())
|
|
99
99
|
self.qzone_tokens[self.login.uin] = r.qzonetoken
|
|
100
100
|
log.debug(f"qzonetoken[{self.login.uin}] = {r.qzonetoken}")
|
|
101
101
|
return r
|
|
@@ -106,12 +106,7 @@ class QzoneH5API:
|
|
|
106
106
|
:param hostuin: uin of the user
|
|
107
107
|
:param start_time: timestamp in seconds, default as current time.
|
|
108
108
|
"""
|
|
109
|
-
r = await self.call(
|
|
110
|
-
UserProfileApi(
|
|
111
|
-
params=ProfileParams(hostuin=hostuin, starttime=int(1e3 * start_time)),
|
|
112
|
-
response=ProfilePagePesp,
|
|
113
|
-
)
|
|
114
|
-
)
|
|
109
|
+
r = await self.call(UserProfileApi(params=ProfileParams.model_validate(locals())))
|
|
115
110
|
self.qzone_tokens[hostuin] = r.qzonetoken
|
|
116
111
|
log.debug(f"qzonetoken[{hostuin}] = {r.qzonetoken}")
|
|
117
112
|
return r
|
|
@@ -127,90 +122,57 @@ class QzoneH5API:
|
|
|
127
122
|
if not self.qzone_tokens.get(self.login.uin) or not attach_info:
|
|
128
123
|
return await self.index()
|
|
129
124
|
|
|
130
|
-
return await self.call(
|
|
131
|
-
FeedPageApi(
|
|
132
|
-
params=ActiveFeedsParams(attach_info=attach_info),
|
|
133
|
-
response=FeedPageResp,
|
|
134
|
-
)
|
|
135
|
-
)
|
|
125
|
+
return await self.call(FeedPageApi(params=ActiveFeedsParams.model_validate(locals())))
|
|
136
126
|
|
|
137
|
-
async def get_feeds(self,
|
|
127
|
+
async def get_feeds(self, hostuin: int, attach_info: t.Optional[str] = None) -> ProfileResp:
|
|
138
128
|
"""Get next page of the given :obj:`uin`.
|
|
139
129
|
If :obj:`.qzone_tokens` has not cached qzonetoken of given :obj:`uin` or :obj:`attach_info` is empty,
|
|
140
130
|
it will call :meth:`.profile` and return its :obj:`~ProfileResp.feedpage` field.
|
|
141
131
|
|
|
142
|
-
:param
|
|
132
|
+
:param hostuin: uin of the user
|
|
143
133
|
:param attach_info: The ``attach_info`` field from last call.
|
|
144
134
|
Pass an empty string equals to call :meth:`.index`.
|
|
145
135
|
:return: If success, the ``data`` field of the response.
|
|
146
136
|
"""
|
|
147
|
-
if not self.qzone_tokens.get(
|
|
148
|
-
return (await self.profile(
|
|
137
|
+
if not self.qzone_tokens.get(hostuin) or not attach_info:
|
|
138
|
+
return (await self.profile(hostuin)).feedpage
|
|
149
139
|
|
|
150
|
-
return await self.call(
|
|
151
|
-
GetFeedsApi(
|
|
152
|
-
params=GetFeedsParams(
|
|
153
|
-
hostuin=uin,
|
|
154
|
-
res_attach=attach_info,
|
|
155
|
-
),
|
|
156
|
-
response=ProfileResp,
|
|
157
|
-
)
|
|
158
|
-
)
|
|
140
|
+
return await self.call(GetFeedsApi(params=GetFeedsParams.model_validate(locals())))
|
|
159
141
|
|
|
160
142
|
async def shuoshuo(self, fid: str, uin: int, appid=311, busi_param: str = "") -> DetailResp:
|
|
161
143
|
"""This can be used to get the detailed summary of a feed.
|
|
162
144
|
|
|
163
|
-
:param fid:
|
|
164
|
-
:param
|
|
165
|
-
:param appid: appid
|
|
145
|
+
:param fid: :term:`fid`
|
|
146
|
+
:param uin: uin of the owner of the given feed
|
|
147
|
+
:param appid: :term:`appid`
|
|
166
148
|
:param busi_param: optional encoded params
|
|
167
149
|
"""
|
|
168
|
-
return await self.call(
|
|
169
|
-
ShuoshuoApi(
|
|
170
|
-
params=ShuoshuoParams(fid=fid, uin=uin, appid=appid, busi_param=busi_param),
|
|
171
|
-
response=DetailResp,
|
|
172
|
-
)
|
|
173
|
-
)
|
|
150
|
+
return await self.call(ShuoshuoApi(params=ShuoshuoParams.model_validate(locals())))
|
|
174
151
|
|
|
175
152
|
async def mfeeds_get_count(self) -> FeedCount:
|
|
176
153
|
"""Get new feeds count. This is also the "keep-alive" signal of the cookie."""
|
|
177
|
-
return await self.call(
|
|
178
|
-
GetCountApi(params=GetCountParams(), response=FeedCount),
|
|
179
|
-
)
|
|
154
|
+
return await self.call(GetCountApi())
|
|
180
155
|
|
|
181
156
|
async def internal_dolike_app(
|
|
182
157
|
self, appid: int, unikey: str, curkey: str, like=True
|
|
183
158
|
) -> SingleReturnResp:
|
|
184
159
|
"""Like or unlike."""
|
|
185
|
-
if like
|
|
186
|
-
path = "/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app"
|
|
187
|
-
else:
|
|
188
|
-
path = "/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_unlike_app"
|
|
160
|
+
cls = LikeApi if like else UnlikeApi
|
|
189
161
|
|
|
190
|
-
return await self.call(
|
|
191
|
-
DoLikeApi(
|
|
192
|
-
path=path,
|
|
193
|
-
params=DolikeParam(appid=appid, unikey=unikey, curkey=curkey),
|
|
194
|
-
response=SingleReturnResp,
|
|
195
|
-
)
|
|
196
|
-
)
|
|
162
|
+
return await self.call(cls(params=DolikeParam.model_validate(locals())))
|
|
197
163
|
|
|
198
164
|
async def add_comment(
|
|
199
|
-
self,
|
|
165
|
+
self, ownuin: int, fid: str, appid: int, content: str, private=False
|
|
200
166
|
) -> AddCommentResp:
|
|
201
|
-
"""Comment a feed.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
),
|
|
211
|
-
response=AddCommentResp,
|
|
212
|
-
)
|
|
213
|
-
)
|
|
167
|
+
"""Comment a feed.
|
|
168
|
+
|
|
169
|
+
:param ownuin: Feed owner uin
|
|
170
|
+
:param fid: :term:`fid`
|
|
171
|
+
:param appid: :term:`appid`
|
|
172
|
+
:param content: comment content
|
|
173
|
+
:param private: is private comment
|
|
174
|
+
"""
|
|
175
|
+
return await self.call(AddCommentApi(params=AddCommentParams.model_validate(locals())))
|
|
214
176
|
|
|
215
177
|
async def publish_mood(
|
|
216
178
|
self,
|
|
@@ -219,17 +181,15 @@ class QzoneH5API:
|
|
|
219
181
|
sync_weibo=False,
|
|
220
182
|
ugc_right: UgcRight = UgcRight.all,
|
|
221
183
|
) -> PublishMoodResp:
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
)
|
|
232
|
-
)
|
|
184
|
+
"""Publish a feed.
|
|
185
|
+
|
|
186
|
+
:param content: feed content
|
|
187
|
+
:param photos:
|
|
188
|
+
:param sync_weibo: sync to weibo, default to false
|
|
189
|
+
:param ugc_right: access right, default to "Available to Everyone".
|
|
190
|
+
"""
|
|
191
|
+
photos = photos or []
|
|
192
|
+
return await self.call(PublishMoodApi(params=PublishMoodParams.model_validate(locals())))
|
|
233
193
|
|
|
234
194
|
async def upload_pic(
|
|
235
195
|
self, picture: bytes, width: int, height: int, quality: int
|
|
@@ -242,29 +202,26 @@ class QzoneH5API:
|
|
|
242
202
|
hd_height=height,
|
|
243
203
|
hd_quality=quality,
|
|
244
204
|
),
|
|
245
|
-
response=UploadPicResponse,
|
|
246
205
|
)
|
|
247
206
|
)
|
|
248
207
|
|
|
249
208
|
async def preupload_photos(
|
|
250
|
-
self,
|
|
209
|
+
self, upload_pics: t.List[UploadPicResponse], cur_num=0, upload_hd=False
|
|
251
210
|
) -> PhotosPreuploadResponse:
|
|
252
|
-
assert
|
|
211
|
+
assert upload_pics
|
|
253
212
|
return await self.call(
|
|
254
|
-
PhotosPreuploadApi(
|
|
255
|
-
params=PhotosPreuploadParams(
|
|
256
|
-
upload_pics=photos,
|
|
257
|
-
currnum=cur_num,
|
|
258
|
-
upload_hd=int(hd),
|
|
259
|
-
),
|
|
260
|
-
response=PhotosPreuploadResponse,
|
|
261
|
-
)
|
|
213
|
+
PhotosPreuploadApi(params=PhotosPreuploadParams.model_validate(locals()))
|
|
262
214
|
)
|
|
263
215
|
|
|
264
216
|
async def delete_ugc(self, fid: str, appid: int) -> DeleteUgcResp:
|
|
217
|
+
"""Delete a feed.
|
|
218
|
+
|
|
219
|
+
:param fid: :term:`fid`
|
|
220
|
+
:param appid: :term:`appid`
|
|
221
|
+
"""
|
|
265
222
|
return await self.call(
|
|
266
223
|
AddOperationApi(
|
|
267
|
-
params=DeleteUgcParams(
|
|
224
|
+
params=DeleteUgcParams.model_validate(locals()),
|
|
268
225
|
response=DeleteUgcResp,
|
|
269
226
|
)
|
|
270
227
|
)
|
|
@@ -14,15 +14,15 @@ TyHttpMethod = t.Union[t.Literal["GET"], t.Literal["POST"]]
|
|
|
14
14
|
class QzoneApi(BaseModel, t.Generic[TyRequest, TyResponse]):
|
|
15
15
|
host: t.ClassVar[str] = "https://h5.qzone.qq.com"
|
|
16
16
|
http_method: t.ClassVar[TyHttpMethod]
|
|
17
|
-
path: str
|
|
17
|
+
path: t.ClassVar[str]
|
|
18
18
|
|
|
19
|
-
keep_alive: bool = True
|
|
20
|
-
accept: t.Optional[str] = None
|
|
19
|
+
keep_alive: t.ClassVar[bool] = True
|
|
20
|
+
accept: t.ClassVar[t.Optional[str]] = None
|
|
21
21
|
referer: str = "https://h5.qzone.qq.com/"
|
|
22
22
|
|
|
23
|
-
attach_token: bool = True
|
|
23
|
+
attach_token: t.ClassVar[bool] = True
|
|
24
24
|
params: TyRequest = Field(default_factory=QzoneRequestParams)
|
|
25
|
-
response: t.Type[TyResponse]
|
|
25
|
+
response: t.ClassVar[t.Type[TyResponse]] # type: ignore
|
|
26
26
|
|
|
27
27
|
@property
|
|
28
28
|
def url(self) -> URL:
|
|
@@ -30,47 +30,62 @@ class QzoneApi(BaseModel, t.Generic[TyRequest, TyResponse]):
|
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
class IndexPageApi(QzoneApi[QzoneRequestParams, IndexPageResp]):
|
|
33
|
+
response: t.ClassVar = IndexPageResp
|
|
33
34
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
34
35
|
path: t.ClassVar[str] = "/mqzone/index"
|
|
35
|
-
keep_alive: bool = False
|
|
36
|
-
attach_token: bool = False
|
|
36
|
+
keep_alive: t.ClassVar[bool] = False
|
|
37
|
+
attach_token: t.ClassVar[bool] = False
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
class UserProfileApi(QzoneApi[ProfileParams, ProfilePagePesp]):
|
|
41
|
+
response: t.ClassVar = ProfilePagePesp
|
|
40
42
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
41
43
|
path: t.ClassVar[str] = "/mqzone/profile"
|
|
42
|
-
keep_alive: bool = False
|
|
43
|
-
attach_token: bool = False
|
|
44
|
+
keep_alive: t.ClassVar[bool] = False
|
|
45
|
+
attach_token: t.ClassVar[bool] = False
|
|
44
46
|
|
|
45
47
|
|
|
46
48
|
class FeedPageApi(QzoneApi[ActiveFeedsParams, FeedPageResp]):
|
|
49
|
+
response: t.ClassVar = FeedPageResp
|
|
47
50
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
48
51
|
path: t.ClassVar[str] = "/webapp/json/mqzone_feeds/getActiveFeeds"
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
class ShuoshuoApi(QzoneApi[ShuoshuoParams, DetailResp]):
|
|
55
|
+
response: t.ClassVar = DetailResp
|
|
52
56
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
53
57
|
path: t.ClassVar[str] = "/webapp/json/mqzone_detail/shuoshuo"
|
|
54
58
|
|
|
55
59
|
|
|
56
60
|
class GetFeedsApi(QzoneApi[GetFeedsParams, ProfileResp]):
|
|
61
|
+
response: t.ClassVar = ProfileResp
|
|
57
62
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
58
63
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
59
64
|
path: t.ClassVar[str] = "/get_feeds"
|
|
60
65
|
|
|
61
66
|
|
|
62
67
|
class GetCountApi(QzoneApi[GetCountParams, FeedCount]):
|
|
68
|
+
response: t.ClassVar = FeedCount
|
|
69
|
+
params: GetCountParams = Field(default_factory=GetCountParams)
|
|
70
|
+
|
|
63
71
|
http_method: t.ClassVar[TyHttpMethod] = "GET"
|
|
64
72
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
65
73
|
path: t.ClassVar[str] = "/feeds/mfeeds_get_count"
|
|
66
|
-
accept: str = "application/json"
|
|
74
|
+
accept: t.ClassVar[str] = "application/json"
|
|
67
75
|
|
|
68
76
|
|
|
69
|
-
class
|
|
77
|
+
class LikeApi(QzoneApi[DolikeParam, SingleReturnResp]):
|
|
78
|
+
response: t.ClassVar = SingleReturnResp
|
|
70
79
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
80
|
+
path: t.ClassVar[str] = "/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_dolike_app"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class UnlikeApi(LikeApi):
|
|
84
|
+
path: t.ClassVar[str] = "/proxy/domain/w.qzone.qq.com/cgi-bin/likes/internal_unlike_app"
|
|
71
85
|
|
|
72
86
|
|
|
73
87
|
class AddCommentApi(QzoneApi[AddCommentParams, AddCommentResp]):
|
|
88
|
+
response: t.ClassVar = AddCommentResp
|
|
74
89
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
75
90
|
path: t.ClassVar[str] = "/webapp/json/qzoneOperation/addComment"
|
|
76
91
|
|
|
@@ -82,24 +97,28 @@ class ListFriendApi(QzoneApi):
|
|
|
82
97
|
|
|
83
98
|
|
|
84
99
|
class PublishMoodApi(QzoneApi[PublishMoodParams, PublishMoodResp]):
|
|
100
|
+
response: t.ClassVar = PublishMoodResp
|
|
85
101
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
86
102
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
87
103
|
path: t.ClassVar[str] = "/mood/publish_mood"
|
|
88
104
|
|
|
89
105
|
|
|
90
106
|
class AddOperationApi(QzoneApi):
|
|
107
|
+
response: t.Type[QzoneResponse]
|
|
91
108
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
92
109
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
93
110
|
path: t.ClassVar[str] = "operation/operation_add"
|
|
94
111
|
|
|
95
112
|
|
|
96
113
|
class UploadPicApi(QzoneApi[UploadPicParams, UploadPicResponse]):
|
|
114
|
+
response: t.ClassVar = UploadPicResponse
|
|
97
115
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
98
116
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
99
117
|
path: t.ClassVar[str] = "/up/cgi-bin/upload/cgi_upload_pic_v2"
|
|
100
118
|
|
|
101
119
|
|
|
102
120
|
class PhotosPreuploadApi(QzoneApi[PhotosPreuploadParams, PhotosPreuploadResponse]):
|
|
121
|
+
response: t.ClassVar = PhotosPreuploadResponse
|
|
103
122
|
http_method: t.ClassVar[TyHttpMethod] = "POST"
|
|
104
123
|
host: t.ClassVar[str] = "https://mobile.qzone.qq.com"
|
|
105
124
|
path: t.ClassVar[str] = "/up/cgi-bin/upload/cgi_upload_pic_v2"
|
|
@@ -48,7 +48,7 @@ class ActiveFeedsParams(QzoneRequestParams):
|
|
|
48
48
|
|
|
49
49
|
class GetFeedsParams(QzoneRequestParams):
|
|
50
50
|
hostuin: int
|
|
51
|
-
|
|
51
|
+
attach_info: str = Field(default="", serialization_alias="res_attach")
|
|
52
52
|
|
|
53
53
|
res_type: int = 2
|
|
54
54
|
refresh_type: int = 2
|
|
@@ -57,9 +57,13 @@ class GetFeedsParams(QzoneRequestParams):
|
|
|
57
57
|
|
|
58
58
|
class ProfileParams(QzoneRequestParams):
|
|
59
59
|
hostuin: int
|
|
60
|
-
|
|
60
|
+
start_time: float = Field(default=0, serialization_alias="starttime")
|
|
61
61
|
ts_fields = ("starttime",)
|
|
62
62
|
|
|
63
|
+
@field_serializer("start_time")
|
|
64
|
+
def ms(self, start_time: float):
|
|
65
|
+
return int(1e3 * start_time)
|
|
66
|
+
|
|
63
67
|
|
|
64
68
|
class ShuoshuoParams(QzoneRequestParams):
|
|
65
69
|
fid: str = Field(serialization_alias="cellid")
|
|
@@ -132,7 +136,9 @@ class PublishMoodParams(QzoneRequestParams):
|
|
|
132
136
|
uin_fields = ("res_uin",)
|
|
133
137
|
content: str = Field(min_length=1, max_length=2000)
|
|
134
138
|
photos: t.List[PhotoData] = Field(default_factory=list, serialization_alias="richval")
|
|
135
|
-
|
|
139
|
+
sync_weibo: int = Field(
|
|
140
|
+
default=False, validate_default=True, serialization_alias="issyncweibo"
|
|
141
|
+
)
|
|
136
142
|
ugc_right: UgcRight = UgcRight.all
|
|
137
143
|
|
|
138
144
|
opr_type: str = "publish_shuoshuo"
|
|
@@ -179,7 +185,7 @@ class PhotosPreuploadParams(QzoneRequestParams):
|
|
|
179
185
|
uin_fields = ("uin",)
|
|
180
186
|
upload_pics: t.List[UploadPicResponse] = Field(exclude=True)
|
|
181
187
|
|
|
182
|
-
|
|
188
|
+
cur_num: int = Field(default=0, serialization_alias="currnum")
|
|
183
189
|
upload_hd: int = 0
|
|
184
190
|
|
|
185
191
|
# defaults
|
|
@@ -11,11 +11,13 @@ from typing_extensions import Self
|
|
|
11
11
|
from aioqzone.exception import QzoneError
|
|
12
12
|
from aioqzone.utils.regex import entire_closing, response_callback
|
|
13
13
|
from qqqr.utils.iter import firstn
|
|
14
|
-
from qqqr.utils.jsjson import json_loads
|
|
14
|
+
from qqqr.utils.jsjson import JsonValue, json_loads
|
|
15
15
|
|
|
16
16
|
from .feed import FeedData
|
|
17
17
|
from .profile import ProfileFeedData, QzoneProfile
|
|
18
18
|
|
|
19
|
+
StrDict = t.Dict[str, JsonValue]
|
|
20
|
+
|
|
19
21
|
__all__ = [
|
|
20
22
|
"QzoneResponse",
|
|
21
23
|
"FeedPageResp",
|
|
@@ -34,11 +36,6 @@ __all__ = [
|
|
|
34
36
|
"ProfileFeedData",
|
|
35
37
|
]
|
|
36
38
|
|
|
37
|
-
if t.TYPE_CHECKING:
|
|
38
|
-
from qqqr.utils.jsjson import JsonValue
|
|
39
|
-
|
|
40
|
-
StrDict = t.Dict[str, JsonValue]
|
|
41
|
-
|
|
42
39
|
|
|
43
40
|
class QzoneResponse(BaseModel):
|
|
44
41
|
_errno_key: t.ClassVar[t.Union[str, AliasPath, AliasChoices, None]] = AliasChoices(
|
|
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
|