dy-cli 0.2.1__tar.gz → 0.2.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.
- {dy_cli-0.2.1 → dy_cli-0.2.2}/PKG-INFO +1 -1
- {dy_cli-0.2.1 → dy_cli-0.2.2}/pyproject.toml +1 -1
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/__init__.py +1 -1
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/search.py +12 -6
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/engines/api_client.py +30 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/.github/workflows/ci.yml +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/.github/workflows/publish.yml +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/.gitignore +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/LICENSE +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/README.md +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/SCHEMA.md +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/SKILL.md +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/activate.sh +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/config/accounts.json.example +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/demo.gif +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/docs/claude-code-integration.md +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/docs/cli-guide.md +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/manifest.json +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/requirements.txt +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/scripts/chrome_launcher.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/scripts/douyin_analytics.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/scripts/douyin_login.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/scripts/douyin_publisher.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/setup.bat +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/setup.sh +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/__init__.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/account.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/analytics.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/auth.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/config_cmd.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/download.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/init.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/interact.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/live.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/profile.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/publish.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/commands/trending.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/engines/__init__.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/engines/playwright_client.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/main.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/__init__.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/config.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/envelope.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/export.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/index_cache.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/output.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/src/dy_cli/utils/signature.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/__init__.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_cli.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_config.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_envelope.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_export.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_index_cache.py +0 -0
- {dy_cli-0.2.1 → dy_cli-0.2.2}/tests/test_signature.py +0 -0
|
@@ -71,13 +71,19 @@ def search(keyword, sort, pub_time, search_type, count, account, as_json, output
|
|
|
71
71
|
data_list = result.get("data", [])
|
|
72
72
|
|
|
73
73
|
if search_type == "user":
|
|
74
|
-
# 用户搜索:
|
|
74
|
+
# 用户搜索: 专用 endpoint 返回顶层 user_list[].user_info
|
|
75
75
|
users = []
|
|
76
|
-
for
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
for u in result.get("user_list", []):
|
|
77
|
+
ui = u.get("user_info", {})
|
|
78
|
+
if ui:
|
|
79
|
+
users.append(ui)
|
|
80
|
+
# Fallback: 综合搜索结果中的用户
|
|
81
|
+
if not users:
|
|
82
|
+
for item in data_list:
|
|
83
|
+
for u in item.get("user_list", []):
|
|
84
|
+
ui = u.get("user_info", {})
|
|
85
|
+
if ui:
|
|
86
|
+
users.append(ui)
|
|
81
87
|
|
|
82
88
|
if output:
|
|
83
89
|
export_data(users, output)
|
|
@@ -38,6 +38,7 @@ VIDEO_COMMENTS_URL = f"{API_DOMAIN}/aweme/v1/web/comment/list/"
|
|
|
38
38
|
USER_PROFILE_URL = f"{API_DOMAIN}/aweme/v1/web/user/profile/other/"
|
|
39
39
|
USER_POSTS_URL = f"{API_DOMAIN}/aweme/v1/web/aweme/post/"
|
|
40
40
|
TRENDING_URL = f"{API_DOMAIN}/aweme/v1/web/hot/search/list/"
|
|
41
|
+
USER_SEARCH_URL = f"{API_DOMAIN}/aweme/v1/web/discover/search/"
|
|
41
42
|
LIVE_INFO_URL = "https://live.douyin.com/webcast/room/web/enter/"
|
|
42
43
|
FEED_URL = f"{API_DOMAIN}/aweme/v1/web/tab/feed/"
|
|
43
44
|
SUGGEST_URL = f"{API_DOMAIN}/aweme/v1/web/api/suggest_words/"
|
|
@@ -332,6 +333,10 @@ class DouyinAPIClient:
|
|
|
332
333
|
offset: 偏移量
|
|
333
334
|
count: 每页数量
|
|
334
335
|
"""
|
|
336
|
+
# 用户搜索使用专用 endpoint
|
|
337
|
+
if search_type == "user":
|
|
338
|
+
return self.search_users(keyword, offset=offset, count=count)
|
|
339
|
+
|
|
335
340
|
params = {
|
|
336
341
|
**get_base_params(),
|
|
337
342
|
"keyword": keyword,
|
|
@@ -354,6 +359,31 @@ class DouyinAPIClient:
|
|
|
354
359
|
|
|
355
360
|
return data
|
|
356
361
|
|
|
362
|
+
def search_users(
|
|
363
|
+
self,
|
|
364
|
+
keyword: str,
|
|
365
|
+
offset: int = 0,
|
|
366
|
+
count: int = 10,
|
|
367
|
+
) -> dict:
|
|
368
|
+
"""搜索用户(使用专用 endpoint)。"""
|
|
369
|
+
params = {
|
|
370
|
+
**get_base_params(),
|
|
371
|
+
"keyword": keyword,
|
|
372
|
+
"search_channel": "aweme_user_search",
|
|
373
|
+
"offset": str(offset),
|
|
374
|
+
"count": str(count),
|
|
375
|
+
"search_source": "normal_search",
|
|
376
|
+
"is_filter_search": "0",
|
|
377
|
+
}
|
|
378
|
+
data = self._get(USER_SEARCH_URL, params=params)
|
|
379
|
+
|
|
380
|
+
if data.get("status_code") != 0:
|
|
381
|
+
raise DouyinAPIError(
|
|
382
|
+
f"用户搜索失败: {data.get('status_msg', 'unknown error')}"
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
return data
|
|
386
|
+
|
|
357
387
|
# ------------------------------------------------------------------
|
|
358
388
|
# Video detail
|
|
359
389
|
# ------------------------------------------------------------------
|
|
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
|
|
File without changes
|