dy-cli 0.2.0__py3-none-any.whl

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.
@@ -0,0 +1,131 @@
1
+ """
2
+ dy search / detail — 搜索和详情命令。
3
+ """
4
+ from __future__ import annotations
5
+
6
+ import json
7
+
8
+ import click
9
+
10
+ from dy_cli.engines.api_client import DouyinAPIClient, DouyinAPIError
11
+ from dy_cli.utils.index_cache import save_index, resolve_id
12
+ from dy_cli.utils.export import export_data
13
+ from dy_cli.utils.output import (
14
+ success, error, info, warning, console,
15
+ print_videos, print_json, print_video_detail, print_comments,
16
+ )
17
+
18
+
19
+ SORT_MAP = {
20
+ "综合": 0,
21
+ "最多点赞": 1,
22
+ "最新发布": 2,
23
+ }
24
+
25
+ TIME_MAP = {
26
+ "不限": 0,
27
+ "一天内": 1,
28
+ "一周内": 7,
29
+ "半年内": 182,
30
+ }
31
+
32
+
33
+ @click.command("search", help="搜索抖音视频")
34
+ @click.argument("keyword")
35
+ @click.option("--sort", type=click.Choice(["综合", "最多点赞", "最新发布"]),
36
+ default="综合", help="排序方式")
37
+ @click.option("--time", "pub_time", type=click.Choice(["不限", "一天内", "一周内", "半年内"]),
38
+ default="不限", help="发布时间")
39
+ @click.option("--type", "search_type", type=click.Choice(["general", "video", "user"]),
40
+ default="general", help="搜索类型")
41
+ @click.option("--count", type=int, default=20, help="结果数量 (默认 20)")
42
+ @click.option("--account", default=None, help="使用指定账号")
43
+ @click.option("--json-output", "as_json", is_flag=True, help="输出 JSON 格式")
44
+ @click.option("-o", "--output", default=None, help="导出到文件 (.json/.csv/.yaml)")
45
+ def search(keyword, sort, pub_time, search_type, count, account, as_json, output):
46
+ """搜索抖音视频/用户。"""
47
+ client = DouyinAPIClient.from_config(account)
48
+ info(f"正在搜索: {keyword}")
49
+
50
+ try:
51
+ result = client.search(
52
+ keyword=keyword,
53
+ sort_type=SORT_MAP.get(sort, 0),
54
+ publish_time=TIME_MAP.get(pub_time, 0),
55
+ search_type=search_type,
56
+ count=count,
57
+ )
58
+ except DouyinAPIError as e:
59
+ error(f"搜索失败: {e}")
60
+ raise SystemExit(1)
61
+ finally:
62
+ client.close()
63
+
64
+ if as_json:
65
+ print_json(result)
66
+ return
67
+
68
+ # Extract video list
69
+ data_list = result.get("data", [])
70
+ videos = []
71
+ for item in data_list:
72
+ aweme_info = item.get("aweme_info")
73
+ if aweme_info:
74
+ videos.append(aweme_info)
75
+
76
+ # 缓存索引 — 支持 dy read 1 / dy download 3
77
+ save_index(videos)
78
+
79
+ # 导出
80
+ if output:
81
+ export_data(videos, output)
82
+ return
83
+
84
+ print_videos(videos, keyword=keyword)
85
+
86
+
87
+ @click.command("detail", help="查看视频详情 (支持短索引: dy detail 1)")
88
+ @click.argument("aweme_id")
89
+ @click.option("--comments", is_flag=True, help="同时加载评论")
90
+ @click.option("--comment-count", type=int, default=20, help="评论数量 (默认 20)")
91
+ @click.option("--account", default=None, help="使用指定账号")
92
+ @click.option("--json-output", "as_json", is_flag=True, help="输出 JSON")
93
+ def detail(aweme_id, comments, comment_count, account, as_json):
94
+ """查看视频详情和评论。支持短索引 (dy search → dy detail 1)。"""
95
+ try:
96
+ aweme_id = resolve_id(aweme_id)
97
+ except ValueError as e:
98
+ error(str(e))
99
+ raise SystemExit(1)
100
+ client = DouyinAPIClient.from_config(account)
101
+
102
+ try:
103
+ info(f"正在获取详情: {aweme_id}")
104
+ video_detail = client.get_video_detail(aweme_id)
105
+
106
+ if as_json and not comments:
107
+ print_json(video_detail)
108
+ return
109
+
110
+ print_video_detail(video_detail)
111
+
112
+ # Load comments if requested
113
+ if comments:
114
+ info("正在加载评论...")
115
+ try:
116
+ comment_data = client.get_comments(aweme_id, count=comment_count)
117
+ comment_list = comment_data.get("comments", [])
118
+
119
+ if as_json:
120
+ print_json({"detail": video_detail, "comments": comment_list})
121
+ else:
122
+ print_comments(comment_list)
123
+ except DouyinAPIError as e:
124
+ warning(f"评论加载失败: {e}")
125
+ info("评论 API 需要签名,可单独用 [bold]dy comments[/] 尝试")
126
+
127
+ except DouyinAPIError as e:
128
+ error(f"获取详情失败: {e}")
129
+ raise SystemExit(1)
130
+ finally:
131
+ client.close()
@@ -0,0 +1,82 @@
1
+ """
2
+ dy trending — 抖音热榜命令(抖音特色功能)。
3
+ """
4
+ from __future__ import annotations
5
+
6
+ import time
7
+
8
+ import click
9
+
10
+ from dy_cli.engines.api_client import DouyinAPIClient, DouyinAPIError
11
+ from dy_cli.utils.export import export_data
12
+ from dy_cli.utils.output import success, error, info, warning, console, print_trending, print_json
13
+
14
+
15
+ @click.command("trending", help="🔥 抖音热榜")
16
+ @click.option("--count", type=int, default=50, help="显示条数 (默认 50)")
17
+ @click.option("--watch", is_flag=True, help="实时刷新模式 (每 5 分钟更新)")
18
+ @click.option("--account", default=None, help="使用指定账号")
19
+ @click.option("--json-output", "as_json", is_flag=True, help="输出 JSON")
20
+ @click.option("-o", "--output", default=None, help="导出到文件 (.json/.csv/.yaml)")
21
+ def trending(count, watch, account, as_json, output):
22
+ """查看抖音热榜。"""
23
+ client = DouyinAPIClient.from_config(account)
24
+
25
+ try:
26
+ if watch:
27
+ _watch_trending(client, count, as_json)
28
+ else:
29
+ _show_trending(client, count, as_json, output)
30
+ except KeyboardInterrupt:
31
+ info("已退出热榜监控")
32
+ except DouyinAPIError as e:
33
+ error(f"获取热榜失败: {e}")
34
+ raise SystemExit(1)
35
+ finally:
36
+ client.close()
37
+
38
+
39
+ def _show_trending(client: DouyinAPIClient, count: int, as_json: bool, output: str = None):
40
+ """显示热榜。"""
41
+ info("正在获取抖音热榜...")
42
+ items = client.get_trending()
43
+
44
+ if as_json:
45
+ print_json(items[:count])
46
+ return
47
+
48
+ if output:
49
+ export_data(items[:count], output)
50
+ return
51
+
52
+ print_trending(items[:count])
53
+
54
+ if items:
55
+ console.print()
56
+ info(f"共 {len(items)} 条热搜,显示前 {min(count, len(items))} 条")
57
+
58
+
59
+ def _watch_trending(client: DouyinAPIClient, count: int, as_json: bool):
60
+ """实时刷新热榜。"""
61
+ interval = 300 # 5 minutes
62
+ info(f"热榜监控模式 (每 {interval // 60} 分钟刷新,Ctrl+C 退出)")
63
+ console.print()
64
+
65
+ while True:
66
+ try:
67
+ items = client.get_trending()
68
+ if as_json:
69
+ print_json(items[:count])
70
+ else:
71
+ console.clear()
72
+ import datetime
73
+ now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
74
+ console.rule(f"[bold]🔥 抖音热榜 — {now}[/]")
75
+ print_trending(items[:count])
76
+ console.print()
77
+ info(f"下次刷新: {interval // 60} 分钟后 (Ctrl+C 退出)")
78
+
79
+ time.sleep(interval)
80
+ except DouyinAPIError as e:
81
+ warning(f"刷新失败: {e}, 等待重试...")
82
+ time.sleep(60)
File without changes