shuadouyin 0.3.4 → 0.3.5

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.
package/.dy-build-commit CHANGED
@@ -1 +1 @@
1
- acefdb95ebb80b24b61632d5874193c29517801a
1
+ 74b35764d458acaeeff44eaef3fe9e9a99941ac8
package/dist/errors.js CHANGED
@@ -74,6 +74,29 @@ export function errorExit(error) {
74
74
  return 1;
75
75
  }
76
76
  }
77
+ // Whether running the same command again could reasonably work.
78
+ //
79
+ // The field was hardcoded false, so it told a caller nothing. The distinction it
80
+ // should carry is the one that decides what to do next: a page that was mid-render
81
+ // is worth one more try, and a changed selector is not — repeating it just spends
82
+ // the same seconds for the same answer.
83
+ //
84
+ // `selector_changed` is deliberately in neither list. It is the one code that
85
+ // covers both a transition and a genuine structural change, and the page adapter
86
+ // already names which happened when it can ("no size", "covered", "not clickable").
87
+ // Marking it retryable would turn a broken page into a loop.
88
+ export function retryable(code) {
89
+ return [
90
+ // The browser or the network was not ready; nothing about the request was wrong.
91
+ "timeout",
92
+ "browser_not_running",
93
+ "browser_unavailable",
94
+ // Another command held the lease. It has since finished.
95
+ "busy",
96
+ // The page had not finished laying out.
97
+ "editor_not_ready",
98
+ ].includes(code);
99
+ }
77
100
  export function errorData(error) {
78
101
  const problem = normalizeError(error);
79
102
  return {
@@ -81,7 +104,7 @@ export function errorData(error) {
81
104
  code: problem.code,
82
105
  message: problem.message,
83
106
  ...(problem.hint ? { hint: problem.hint } : {}),
84
- retryable: false,
107
+ retryable: retryable(problem.code),
85
108
  ...(problem.details === undefined ? {} : { details: problem.details }),
86
109
  };
87
110
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shuadouyin",
3
- "version": "0.3.4",
3
+ "version": "0.3.5",
4
4
  "packageManager": "pnpm@10.34.7",
5
5
  "description": "Browse Douyin with a persistent bot persona and a memory of its own",
6
6
  "type": "module",
@@ -8,6 +8,10 @@ allowed-tools: Bash(dy:*) Bash(npx dy:*)
8
8
 
9
9
  `dy` 是本地能力工具。当前 agent 负责理解、判断、对话、总结与调度。用 `dy schema` 查看可用命令;尊重用户当前授权和已有账号状态。
10
10
 
11
+ **这份文件是常驻的,所以只放每次都用的东西。** 完整的命令说明、平台事实、各场景流程在 `dy guide` 里,它的内容和你的 `dy` 版本永远一致——本文件可能落后于一次更新。拿不准某个命令怎么用,先跑 `dy guide`,别猜。
12
+
13
+ 下面的命令列表够日常使用。遇到没列到的、或者行为和这里写的不一样,以 `dy guide` 和实际返回为准。
14
+
11
15
  ## 第一次用:先问人设
12
16
 
13
17
  新工作区里人格还是模板。这时候每个页面命令的返回里都会带一个 `setup` 字段:
@@ -65,120 +69,37 @@ dy video info # 读当前作品
65
69
 
66
70
  ## 命令
67
71
 
68
- 所有命令返回一个 `{ok:true,data}` 信封;失败是 `{ok:false,error}` 加非零退出。`dy schema` 给全部命令和参数,`dy <命令> --help` 给单个。
69
-
70
- ### 刷与看
71
-
72
- ```bash
73
- dy feed open # 打开推荐流
74
- dy feed next # 下一条;核实 ID 变了才算成功
75
- dy feed previous
76
- dy feed sweep --count 10 # 一次走 10 条,返回 id/作者/标题/时长
77
- ```
78
-
79
- **`feed sweep` 是读一批的首选。** 一条命令、一次连接,`stopped` 说明为什么停下(`count_reached` / `steps_exhausted` / `feed_stuck`)。它不快多少(瓶颈是页面过渡,一次几秒),但一次拿全数据,不用逐条 `video info`。
80
-
81
- ### 判断一条作品在讲什么
82
-
83
- ```bash
84
- dy video digest # 标题 + 三个位置的画面 + 评论区摘要
85
- dy video digest --frames 0 # 只读评论,不采样
86
- dy video seek --at 120 # 跳到第 120 秒
87
- dy video observe --at 200 --seconds 4 --frames 2
88
- ```
89
-
90
- `digest` 约 3–4 秒。三个位置是 25%/50%/75%,避开开头封面语和结尾求关注。实测一条 4 分钟英语视频,三帧字幕拼起来就是完整观点,比标题信息量大得多。
91
-
92
- `--frames 0` 只对 `digest` 有效,`observe` 至少要 1 帧。15 秒以下的作品不采样:`frames` 为空并附一条限制说明,那是设计如此,不是失败。`comments.count` 只数页面已加载的,同一条作品连读两次可能不一样。
93
-
94
- ### 读作品与评论
72
+ 日常这一组就够。参数细节、每个命令的坑、各场景的完整流程都在 `dy guide`。
95
73
 
96
74
  ```bash
97
- dy video info # 当前作品的身份、播放状态、时长
75
+ # 刷与看
76
+ dy feed sweep --count 8 # 一次读一批:id/作者/标题/时长,首选
77
+ dy feed next / previous
78
+ dy video digest # 标题 + 采样画面 + 评论摘要;图集会逐页拍
98
79
  dy video open <id-or-url>
99
- dy comment list --limit 20 # 每条带 stance 和 likes
100
- dy comment replies --comment-id <id>
101
- dy comment delete --comment-id <id> --confirm # 删自己发的一条,不可撤销
102
- dy page scroll --target comments --pixels 600
103
- ```
104
-
105
- `comment list` 每条带 `stance`(`about_work` / `about_self` / `asking` / `spam` / `unknown`)和 `likes`。回之前看 stance,对着「在说自己」的评论夸「唱得好」是错位的。
106
-
107
- **它自己开的面板会自己关**,所以读完能直接 `feed next`。面板挡着翻页箭头时用 `dy comment close`。
108
-
109
- `comment delete` 只删自己的评论,别人的 id 会直接拒绝。**页面不会问你第二次**,点了就没,所以 `--confirm` 是唯一的闸。
110
-
111
- ### 学这个区的写法
112
-
113
- ```bash
114
- dy comment voice --limit 20 # 中位长度、感叹号习惯、称呼、人称、提问比例
115
- dy comment voice --save # 连同句式一起存下来
116
- dy comment voice --known # 已经学过的区,按形状归并
117
- dy comment phrases # 哪些句式还能用
118
- dy comment phrases --use "…" # 记一次使用
119
- ```
120
-
121
- **按作品算,不按全局算。** 同一个号上,不同区的评论中位长度可以差好几倍:一个区可能七八个字,另一个区要写满四五十个字。所以别把上个区学到的语气带到这个区,每换一条作品重新量。
122
80
 
123
- 具体数字每次都不一样,跑一次看 `profile.length.median`,不要信这里举例的数。
124
-
125
- `comment voice` 还给每条评论判 `has-wit` / `flat` / `generic-praise`,依据是接话、具体指认、反转三个维度,以及堆砌术语。实测一个区里 247 赞的是「下次一起唱」,150 字堆术语那条只有 2 赞,长度和赞数相关 -0.38。
126
-
127
- **句式用三次会自动标成 `spent`**,静默 14 天回来。别反复用同一条。
128
-
129
- ### 写
130
-
131
- ```bash
81
+ # 评论
82
+ dy comment list --limit 20 # 每条带 stance 和 likes
132
83
  dy comment post --video-id <id> --text "…" --request-id <唯一ID>
133
84
  dy comment reply --video-id <id> --comment-id <id> --text "…" --request-id <唯一ID>
134
- dy video like --video-id <id> --value true
135
- dy video favorite --video-id <id> --value true
136
- dy user follow --user-id <id> --value true
137
- ```
138
-
139
- 写入必须有 `--request-id`。加 `--progress` 看每一步走到哪,`dispatching` 是分水岭:之前失败什么都没发,之后不可逆。
140
-
141
- ```bash
142
- dy --progress --request-id <id> chat send --conversation-id <id> --text "…"
143
- ```
144
-
145
- ### 直播
146
-
147
- ```bash
148
- dy live info # 主播、开播状态、能否评论
149
- dy live chat --limit 20 # 当前加载的弹幕
150
- dy live say --text "…" --request-id <id>
151
- dy live gifts # 礼物和价格
152
- dy live gift --name 人气票 --price 1 --request-id <id>
153
- ```
154
-
155
- 礼物会花真钱,`--name` 和 `--price` 必须同时匹配。
156
-
157
- ### 记忆
158
-
159
- ```bash
160
- dy memory add --text "…" --source "user:…" --layer … --certainty …
161
- dy memory search <词>
162
- dy memory list
163
- dy memory candidates --text-file <文件>
164
- dy memory decide --text-file <文件> --apply --request-id <id>
85
+ dy comment delete --comment-id <id> --confirm
86
+ dy comment voice # 这个区的写法:中位长度、标点、称呼
87
+ dy voice check --text "…" # 发之前自查像不像机器写的
88
+
89
+ # 私信与关系
90
+ dy chat list / read / send
91
+ dy person read <id> # 这个人发过什么、写过什么
92
+ dy social response --conversation-id <id> # 我发的有没有人回
93
+ dy social advise <person> --conversation-id <id> # 继续、等、还是停
94
+
95
+ # 其他
96
+ dy live info / chat / say
97
+ dy memory add / search
165
98
  dy context show --query "…"
99
+ dy ai ask --query "…" # 问平台自己的 AI,当线索用
166
100
  ```
167
101
 
168
- ### 起步与检查
169
-
170
- ```bash
171
- dy auth login # 扫码登录(有头 Chrome)
172
- dy auth status
173
- dy browser start / stop / status
174
- dy browser clean # 回收磁盘:缓存和截图,不碰登录
175
- dy diagnostics # 反复失败的命令
176
- dy page facts # 页面此刻真实的状态
177
- dy update --check # 有没有新版本
178
- dy skill install # 装 skill 到 agent 目录
179
- ```
180
-
181
- 其余的就:`dy init` 建工作区,`dy guide` 输出完整文档。`dy source` 只对开发 dy 的人有意义。
102
+ **写入必须有 `--request-id`。** 加 `--progress` 看每步走到哪,`dispatching` 之后不可逆。
182
103
 
183
104
  ## 按任务读参考
184
105
 
@@ -20,14 +20,22 @@ dy video digest
20
20
 
21
21
  **按长度分档:**
22
22
 
23
- | 时长 | 策略 |
24
- | --- | --- |
25
- | < 15s | `digest` 自动不采样,`frames` 为空且 `limitations` 说明原因 |
26
- | 15–45s | 只看中间一帧(`--frames 1`) |
27
- | 45s–3min | 三帧够用 |
28
- | > 3min | 三帧 + 评论区,必要时再补 `video observe` |
29
-
30
- **短作品没有帧不等于没看。** `frames: []` 配上「< 15s」的限制说明是设计如此——短内容本身就是全部。别当成采样失败去重试。
23
+ 采样数跟着时长走,不是固定三帧:
24
+
25
+ | 时长 | 帧数 | 说明 |
26
+ | --- | --- | --- |
27
+ | < 15s | 0 | 短内容本身就是全部,`frames: []` 配 `limitations` 说明原因 |
28
+ | 15–45s | 1 | 取正中 |
29
+ | 45s–3min | 3 | 分布在中间 80% |
30
+ | > 3min | 每 2 分钟 +1,上限 8 | 20 分钟的访谈取 8 帧 |
31
+
32
+ **不要用三帧衡量长视频。** 半小时的演讲取三点,等于只看开场、中间一瞥、结尾,论证全丢。既然命令已经按长度算好了,读 `frames` 的长度就知道有没有看够。
33
+
34
+ **`--frames N` 可以压过自动值**,但最低 1 帧。只想看一个位置就传 1。
35
+
36
+ **图集是另一回事。** `digest` 遇到图片帖会逐页截图,一页都不少,因为整条作品就是那组图。
37
+
38
+ **短作品没有帧不等于没看。** `frames: []` 配上「< 15s」的限制说明是设计如此。别当成采样失败去重试。
31
39
 
32
40
  **论坛区比标题更接近真相。** 一条手势舞标题是「我的世界你就是那中心点」,评论区里作者在问「这一版萌还是上一版萌」——那是连载作品,标题没说。看 `stance` 判断观众在说什么:`about_work` 才是在聊作品,`about_self` 是在聊自己。
33
41