cortico-world-mosey 2.0.1 → 2.0.3
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/CHANGELOG.md +44 -34
- package/README.md +2 -2
- package/describe.json +1 -1
- package/package.json +1 -2
- package/src/ENV_PROMPT.md +3 -3
- package/src/bilibili.js +1 -1
- package/src/douyin.js +13 -13
- package/src/tools.js +1 -1
- package/src/world.js +14 -14
- package/docs/comments-sheet.png +0 -0
- package/docs/detail-sheet.png +0 -0
- package/docs/life-section.png +0 -0
- package/docs/panel-preview.html +0 -556
- package/docs/panel-preview.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
# 更新日志
|
|
2
2
|
|
|
3
|
+
## 2.0.3
|
|
4
|
+
|
|
5
|
+
**继续脱敏,并瘦身。** 上一次漏了 `docs/` 里的面板预览页(假数据里有真实昵称和 B站 uid)。现在预览页也换成虚构占位,并且 `docs/` 不再随 npm 包分发——那几张截图只是市场素材,没必要塞进安装包(顺带把安装包瘦了 1.5MB)。
|
|
6
|
+
|
|
7
|
+
## 2.0.2
|
|
8
|
+
|
|
9
|
+
**文档脱敏。**
|
|
10
|
+
|
|
11
|
+
更新日志、README、提示词和配置项说明里的示例昵称,全部换成虚构占位(以前用的是真实账号的昵称,不该跟着包发出去)。功能没有任何变化。
|
|
12
|
+
|
|
3
13
|
## 2.0.1
|
|
4
14
|
|
|
5
15
|
**修两个问题:私信被发到群里、列表里看得见却发不出去(都是群友报的)。**
|
|
6
16
|
|
|
7
17
|
### 群名是「几个人的昵称拼起来」时,私信会发到群里
|
|
8
18
|
|
|
9
|
-
|
|
19
|
+
抖音拉群时群名默认是成员昵称拼的(`小鹿、阿柚、老K`),而群名匹配允许「她写的是群名的一部分」,于是 `target=小鹿` 被判成「发到那个群」——**私信内容直接公开在群里**。
|
|
10
20
|
|
|
11
21
|
- 私信和发表情都改成**先认人、再认群**:命中「给她发过消息的陌生人」就不再做群匹配。想发到这种群,把完整群名写出来。
|
|
12
|
-
-
|
|
22
|
+
- 反过来也修了:主列表差集不再把「小鹿」当成群「小鹿、阿柚」——以前那个人的私信会被整条排除,**永远发现不了**。
|
|
13
23
|
- 新增 `stroll target ambiguous` 日志:一个名字同时像人又像群时,写明最后按哪个发的。
|
|
14
24
|
|
|
15
25
|
### 列表里明明看得见,发的时候说找不到会话
|
|
16
26
|
|
|
17
|
-
-
|
|
27
|
+
- 会话标题黏着时间(`小鹿 昨天`、`小鹿 00:30`)时,精确匹配永远不成立,只能退到「包含」;而群名也可能是成员昵称拼的(`群A、小鹿`),一包含就命中两条 → 判成「歧义」直接放弃。现在先剥掉尾部时间再比。
|
|
18
28
|
- 会话被新消息刷到列表很下面时,抖音的**虚拟滚动**根本不渲染那一行,`querySelectorAll` 看不到。现在找不到会先滚回顶部,再一屏一屏往下找(最多 10 屏)。
|
|
19
29
|
- 顺手:target 就是她自己登录的抖音号时,直接说「抖音不能给自己发私信」,不再报「找不到会话」让她猜。
|
|
20
30
|
|
|
@@ -36,7 +46,7 @@
|
|
|
36
46
|
- 包含比对加长度门槛:少于 4 个字不参与「包含」判断(完全相同的短句仍算她说的)。
|
|
37
47
|
- 一次性重置:启动时把 2 小时内「用正确逻辑看明显不是她说的」指纹删掉,让下一拍重新发现一次(`stroll seen reset`)。
|
|
38
48
|
- `skip` 日志现在带 `hit`:命中的是哪句她说过的话,误判时不用再猜。
|
|
39
|
-
- **待批记录里的昵称也洗了**:以前只洗「陌生人名单」,`strangerPending` 里还存着
|
|
49
|
+
- **待批记录里的昵称也洗了**:以前只洗「陌生人名单」,`strangerPending` 里还存着 `小鹿 刚刚` 这种带时间的昵称——点「让她回」会拿这个名字去发,会话永远找不到。现在新增时统一洗,历史数据启动时清洗并合并同人的重复条目。
|
|
40
50
|
|
|
41
51
|
### 陌生人私信、额度卡、安全收紧
|
|
42
52
|
|
|
@@ -63,19 +73,19 @@
|
|
|
63
73
|
实现上:
|
|
64
74
|
|
|
65
75
|
- 抖音的陌生私信**单独收在「陌生人消息」文件夹里**,主会话列表根本看不到。现在的做法是:先读入口上的预览判断有没有新东西,有才点进文件夹读列表,读完点返回箭头退回主列表(实测退回后能正常点回主人会话)。
|
|
66
|
-
-
|
|
76
|
+
- 解析用「时间」当锚点切昵称和预览——群名带空格(`群B 3`)、时间写成「7分钟前」都能切对,行尾的未读数会剥出来。
|
|
67
77
|
- 回复时如果主列表找不到这个会话,会去「陌生人消息」文件夹里点开再发。
|
|
68
78
|
- 10 秒内最多扫一次会话列表,不加重页面负担。
|
|
69
79
|
- B站读会话列表里的未读会话(非主人),复用本来就有的那一次请求,不多打接口。
|
|
70
80
|
- 首次见到某个会话只记基线,不会把攒了几天的历史私信一次全推。
|
|
71
81
|
- 自己发的最后一句(预览以她自己昵称开头)不会被当成对方来消息。
|
|
72
|
-
- **「她回不了陌生人」修好了**:以前发送时只认群和主人,`target
|
|
82
|
+
- **「她回不了陌生人」修好了**:以前发送时只认群和主人,`target=小鹿` 会被判成「没认出是哪个群」,她就说「陌生人除了那格,别处都不认」。现在发送前会先在她收到的陌生人名单里找人(名单里没有就去文件夹里现查一次),找到就按昵称点进会话回;没给她发过消息的人仍然发不出去。
|
|
73
83
|
- 图片和表情包也能发给陌生人(同样只限给她发过消息的人),不再只认群和主人。
|
|
74
84
|
- **她自己会盯着陌生人了(1 秒一拍)**:以前只靠页面事件,抖音把入口换成红点时观察器不动,就一直发现不了。现在单开一条轻量定时器,每 1 秒读一次入口(纯读页面,不发请求),入口红点变了也算新消息;安静时段不吵她。主列表差集 10 秒一次、文件夹仍然只在有新东西时才点开,不会把页面折腾坏。
|
|
75
85
|
- **面板自己会刷了**:以前「待你点头」就算写进去了,也得你手点「刷新」才看得见。现在每秒轻量查一次待办(只读内存,不查登录态),1 秒内自己冒出来。
|
|
76
86
|
- 点开「陌生人消息」文件夹的两处写死等待(700ms / 900ms)改成条件等待(50ms 一轮),给陌生人的第一条回复快 1 秒多。
|
|
77
87
|
- **修掉两个线上 bug**:
|
|
78
|
-
-
|
|
88
|
+
- 主列表兜底把列表上的时间黏进了昵称(`小鹿 刚刚`),名字每分钟变一次 → 找不到会话 → 发送走了最慢的兜底,实测一次花了 **9 秒**。现在统一剥掉时间,历史数据启动时自动清一遍。
|
|
79
89
|
- **推送死循环**:她自己回完一句,列表最后一句就变成她的话,又被当成「对方发来新消息」推给她,她就一直回自己的话(一天推了 20 次)。现在去重指纹只看正文(不再带「9分钟前」这种会变的文案)、会拿发出去的原文比对「这是不是我说的」、回完某个人 3 分钟内不再推他。
|
|
80
90
|
- 标题读不出来时不再硬发:陌生人这条路径改成「认不出就不发」,报 `THREAD_DRIFT`,避免把话打进别人的会话。
|
|
81
91
|
- **回陌生人提速**:
|
|
@@ -113,7 +123,7 @@
|
|
|
113
123
|
- **常驻页数量做成了设置**(私信与群 → 陌生人常驻页数量,0-4,默认 2)。每个常驻页 = 一个后台标签页(约 50-100MB);填 0 = 不开,省内存。
|
|
114
124
|
- **修掉「常驻页一直建不起来」**(日志里全是 `stroll stranger page { ok: false }`):
|
|
115
125
|
- 新开的页面还没渲染出「陌生人消息」入口就去找,直接判失败 → 现在先等入口出现(最多 6 秒);
|
|
116
|
-
-
|
|
126
|
+
- 文件夹里那一行的标题黏着时间(`小鹿 刚刚`),整串相等永远不成立 → 现在先剥掉时间再比。
|
|
117
127
|
- **表情只看名字也去取图**:抖音有些表情不是 `<img>`,而是 div 的 background-image(还有些是加密下发的),那种元素里 `img` 数量是 0,旧逻辑会当成文字。现在只要整条是 `[名称]`,就走取图那条路(canvas / blob / 背景图都会试一遍)。
|
|
118
128
|
- **修掉「有些账号根本没有陌生人文件夹」导致的连锁失败**(日志里 `hasBox: false`):这类账号对方的会话就在主列表里,而常驻页只会去点「陌生人消息」文件夹 → 永远建不起来(`stroll stranger page ok: false`)→ 一直读不到图。现在文件夹点不到会退回主列表点击。
|
|
119
129
|
- **内容核对认得任意表情名**:以前只认「[表情]」「[图片]」这类关键词,`[大力拥抱]` 这种名字对不上,读到了也会被安全校验丢掉。现在整条是 `[名称]` 就算对得上。
|
|
@@ -453,7 +463,7 @@ due = ended || (dur > 0 && waited >= dur + 3) || waited >= 90;
|
|
|
453
463
|
|
|
454
464
|
**「发一遍」失败:不是没有功能,是抖音的上传被节流了。**
|
|
455
465
|
|
|
456
|
-
翻了 12:57-12:59 的动作记录:同一个 `recv-48bbc047.webp`,12:57
|
|
466
|
+
翻了 12:57-12:59 的动作记录:同一个 `recv-48bbc047.webp`,12:57 发到群B 成功、12:57/12:58 两次 NOT_SENT、12:59 发到主人又成功。失败现场的 dump 里**没有确认弹层、也没有预览图**——说明文件根本没被选进去,不是点错按钮。
|
|
457
467
|
|
|
458
468
|
三处一起改:
|
|
459
469
|
|
|
@@ -596,7 +606,7 @@ stroll image url missing (dm|group)
|
|
|
596
606
|
### 回复提速(插件这一侧)
|
|
597
607
|
|
|
598
608
|
- `body.innerText` → 只查弹层/toast/验证码 iframe。整页 innerText 会强制重排,聊天记录一多就是几百毫秒,而它每次发完消息都要跑。
|
|
599
|
-
-
|
|
609
|
+
- 会话标题比对容忍「群C(3)」「群C 3人」这类后缀。以前对不上就会白点一次会话:多一次点击 + 220ms 等待 + 输入框重建的 400ms,一次白花半秒多。
|
|
600
610
|
- 等输入框的轮询 400ms → 120ms;输入框点击跳过可点性检查(force)。
|
|
601
611
|
- 只解析最新 `2n` 条消息(以前整屏几百条每条都走一遍 React props)。
|
|
602
612
|
- 推送文案压缩:去掉那一大段「别先查 status/feed…」,模型的上下文短了,首字也快一点。
|
|
@@ -611,15 +621,15 @@ stroll image url missing (dm|group)
|
|
|
611
621
|
```
|
|
612
622
|
dm text="在。怎么了。" → 私信主人(没写 target)
|
|
613
623
|
dm text="看到了。又一个群。" → 私信主人(没写 target)
|
|
614
|
-
dm target="
|
|
624
|
+
dm target="阿柚" text="回了…" → 群里(被当成了群一)
|
|
615
625
|
dm text="刚回了,是不是你那边没刷出来。" → 私信主人(没写 target)
|
|
616
626
|
```
|
|
617
627
|
|
|
618
628
|
三个原因叠在一起:
|
|
619
629
|
|
|
620
630
|
- **没写 target 就默认私信主人**。她在回群消息,但手上没填 target,系统一路掉到「私信主人」,还回执「发出去了」。群二当然一条都没有。
|
|
621
|
-
- **target 写主人的昵称会被群名匹配走**。她写 `target="
|
|
622
|
-
- **群二根本没被发现**。日志里只有 `groups detected ['
|
|
631
|
+
- **target 写主人的昵称会被群名匹配走**。她写 `target="阿柚"`(主人的名字),而群标题是「阿柚, 阿澈, 老K」——包含匹配直接命中群一。她以为在私信主人,实际发进了群。
|
|
632
|
+
- **群二根本没被发现**。日志里只有 `groups detected ['阿柚, 阿澈, 老K']` 一个群;`matchGroup` 又允许「反向包含」,写更长的群二名字时会命中更短的群一。于是所有回复都进了群一。
|
|
623
633
|
|
|
624
634
|
改法:
|
|
625
635
|
|
|
@@ -657,7 +667,7 @@ dm text="刚回了,是不是你那边没刷出来。" → 私信主人
|
|
|
657
667
|
<div class="MsgInputMentionmentionContainer"> ← 真正撑开的是这层
|
|
658
668
|
<div class="MentionMentionItemcontainer">
|
|
659
669
|
<div class="MentionMentionIteminnerContainer">…头像 + 「群主」标签…</div>
|
|
660
|
-
<span class="MentionMentionItemuserName"
|
|
670
|
+
<span class="MentionMentionItemuserName">阿柚</span>
|
|
661
671
|
```
|
|
662
672
|
|
|
663
673
|
上一版拿**外层容器**的尺寸判断「面板开没开」:外层 0 高 → 直接返回 `count: 0` → 回执「没找到选人面板」。她照着回执说「抖音这边 @ 面板打不开」,其实面板就在那儿。
|
|
@@ -665,7 +675,7 @@ dm text="刚回了,是不是你那边没刷出来。" → 私信主人
|
|
|
665
675
|
- 不再看容器尺寸,把几层 mention 容器里的行全收上来
|
|
666
676
|
- **首选名字节点** `[class*="userName"]`:文字就是昵称本身,比猜「哪一层是整行」稳得多(整行的高度/宽度随样式变,名字节点不变)
|
|
667
677
|
- 点也点名字那一截(事件冒泡到整行);名字点不动就改点整行;locator 点不中再用坐标兜底
|
|
668
|
-
- 用线上那份 HTML 做了离线回归:3
|
|
678
|
+
- 用线上那份 HTML 做了离线回归:3 个人全认出来,`阿柚`(带「群主」标签)、`老K`、`群聊小助手` 都能精确命中,点击坐标落在候选行内
|
|
669
679
|
- 顺带:从表情面板选中后,**先关掉遮罩再回车**——遮罩挡着输入框,回车根本进不去(这也是「点了表情没反应」的一个原因)
|
|
670
680
|
- 发表情失败现在也会写进动作记录(`[表情没发出去]` + code + dump 路径),不再只有一句「试了四五次都不行」
|
|
671
681
|
|
|
@@ -677,13 +687,13 @@ dm text="刚回了,是不是你那边没刷出来。" → 私信主人
|
|
|
677
687
|
|
|
678
688
|
```
|
|
679
689
|
semi-modal-wrap semi-modal-wrap-center
|
|
680
|
-
「发送给
|
|
690
|
+
「发送给 阿柚, 阿澈, 老K(3) s_811c597ed5c8.png 118.2 KB 取消 发送(1)」
|
|
681
691
|
```
|
|
682
692
|
|
|
683
693
|
- **发图少点了最后一步**:抖音选完图不是直接发,而是先弹确认框,点「发送(1)」才真的发。上一版只看输入区有没有预览、有没有新消息,没认这个框,于是回执写「图选上了但没确认发出去」,界面上其实什么都没发。现在一边等消息变化、一边盯着这个框,看到就点;`via` 会是 `upload+modal`。
|
|
684
694
|
- **表情面板是 semi-modal,Escape 关不掉**:它一直开着挡在输入区上面,后面点什么都点不到。新增 `closeChatModals()`(点遮罩),发图前、收完表情后都会关。
|
|
685
|
-
- **@ 失败的真相:她压根没传 `mention`**。三次 `mentioned:false` 里两次连 dump 都没有,说明 `mentionInChat`
|
|
686
|
-
- 兜底:群标题没起名时就是成员名拼的,从里面拆名单;正文开头对上谁的名字,就当成 @
|
|
695
|
+
- **@ 失败的真相:她压根没传 `mention`**。三次 `mentioned:false` 里两次连 dump 都没有,说明 `mentionInChat` 根本没被调用——她把名字写进正文(「老K,在吗,这么晚还没睡。」)就当 @ 过了。
|
|
696
|
+
- 兜底:群标题没起名时就是成员名拼的,从里面拆名单;正文开头对上谁的名字,就当成 @ 目标并把名字从正文里剥掉。`老K,在吗` → `mention=老K`、正文 `在吗`
|
|
687
697
|
- 语义也改清楚:**没要求 @ 时回执是 `mentioned: null`**,不再是 `false`——`false` 只代表「要求了但没插上」,别再把两者混成一句「@ 没生效」
|
|
688
698
|
- 提示词加硬规则:只在正文里写名字不算 @;不许再说「抖音这边我只能写字」「这条路我走不通」
|
|
689
699
|
|
|
@@ -703,27 +713,27 @@ semi-modal-wrap semi-modal-wrap-center
|
|
|
703
713
|
- SVG 的 `className` 是对象,直接拼字符串会变成 `[object SVGAnimatedString]`,发送按钮因此认不出来 —— 改用 `getAttribute('class')`
|
|
704
714
|
2. **发图片不再依赖点图标**。输入区里一直挂着两个隐藏的 `input[type=file]`,直接把文件塞进去就能上传(实测这条最稳,也最快);点图标 + 接系统文件框降级成兜底。
|
|
705
715
|
3. **@ 的候选行没有宽高上限了**。面板那一行是整条 1104 宽,旧的兜底逻辑卡了「宽 90-620」,所以「面板明明开着,却说没候选」。现在只要求 ≥60 宽;头像也不是必要条件(没有头像时按文字行认)。
|
|
706
|
-
-
|
|
716
|
+
- 顺手修掉一个漏人的坑:以前「子元素文字一样就当外壳整行丢掉」,名字前面**没有**身份标签的人(比如「老K」)会被自己的名字 span 顶掉,名单里直接少一个人。现在先收全部候选,再按文字去重、留最宽的那行。
|
|
707
717
|
4. **@ 改成「先打一个 @,等名单,再点人」**。以前一口气把「@昵称」全打进去,面板还没拉完就被顶掉了。现在先单独敲 `@`,轮询等候选名单,按昵称挑人(剥掉「群主 / 管理员」标签),用 locator 点中那一行(坐标会随面板重绘飘),插成功后再补一个**空格**——就是主人说的「@ 后面没有空格」。
|
|
708
718
|
5. **点完怎么算成功**:手打的 `@名字` 一定落在 `data-string` 叶子里;选中候选后这片叶子会被 chip 替换。叶子还在 = 假 @,返回 `mentioned: false` 并清空输入框,绝不留一个看着像 @ 的蓝字。
|
|
709
719
|
6. 失败时 dump 里多存两份:`mentionHtml`(@ 面板长什么样)和 `actionsHtml`(工具栏长什么样),回执里也带上 dump 路径。
|
|
710
720
|
|
|
711
721
|
## 1.8.1
|
|
712
722
|
|
|
713
|
-
**@ 不到主人的真正原因找到了:候选行写的是「群主
|
|
723
|
+
**@ 不到主人的真正原因找到了:候选行写的是「群主 阿柚」。**
|
|
714
724
|
|
|
715
|
-
她把真 @
|
|
725
|
+
她把真 @ 插进去了,只是插的是「老K」;一到主人就失败。翻了两次失败时落盘的 DOM,面板就在那儿,只有一行:
|
|
716
726
|
|
|
717
727
|
```
|
|
718
|
-
outerText: "群主
|
|
728
|
+
outerText: "群主 阿柚"
|
|
719
729
|
class: MsgInputMentionmentionContainer
|
|
720
730
|
```
|
|
721
731
|
|
|
722
|
-
|
|
732
|
+
老代码拿整行文字跟昵称做**全等比较**,`群主阿柚 !== 阿柚`,永远对不上;「老K」前面没有角色标签,所以一次就成了——跟她说的完全一致。
|
|
723
733
|
|
|
724
734
|
- **候选行先剥身份标签再比**(群主 / 管理员 / 群成员 / 成员 / owner / admin,前后都剥),再按「全等 → 唯一前缀 → 唯一包含」三级匹配;不认类名的兜底也一起改了
|
|
725
735
|
- **「@你」不是昵称**:她不知道主人的抖音名,就写「@你」「@主人」——候选里当然没有这个人,发出去只是一串没有效果的蓝字。现在这几个词一律当「主人」处理,正文里的 `@你 / @主人` 会被剥掉;`mention: "你"` 也认
|
|
726
|
-
- **正文开头手打的 `@某人` 当成 @ 目标**:`text="
|
|
736
|
+
- **正文开头手打的 `@某人` 当成 @ 目标**:`text="@老K 在吗"` 且没传 `mention` 时,自动把它当 `mention` 去插真 chip,而不是发一串蓝字
|
|
727
737
|
- 提示词补硬规则:不知道主人抖音名很正常,**不许猜、不许写「@你」**,直接用 `mention_owner: true`
|
|
728
738
|
|
|
729
739
|
**表情面板点错地方了,这次按几何找。**
|
|
@@ -736,7 +746,7 @@ class: MsgInputMentionmentionContainer
|
|
|
736
746
|
|
|
737
747
|
**图片发出去被判成失败(其实已经发出去了)。**
|
|
738
748
|
|
|
739
|
-
dump
|
|
749
|
+
dump 里能看见:消息预览已经是「阿澈:[图片]」,同时还弹了「不能发送空白消息」——图片消息不带 `msg-item-content`,老判据数不到,以为没发出去,又按了一次回车。
|
|
740
750
|
|
|
741
751
|
- 判据换成 `chatSig`:`[data-e2e^="msg-item"]` 条数 + 末尾文字 + 图片数,图片/表情消息都能认
|
|
742
752
|
- **只有输入框里真有字才回车**,空着回车会弹「不能发送空白消息」
|
|
@@ -797,7 +807,7 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
797
807
|
主人在群里看到她发「@ 你了」,那个 @ 是蓝的,但后面不带名字、也没有任何通知。查了动作日志,她实际发出去的是:
|
|
798
808
|
|
|
799
809
|
```
|
|
800
|
-
'
|
|
810
|
+
'@老K 在吗,阿澈。月让我在你这个群里@你一下。'
|
|
801
811
|
'好,@ 你了。收到没。'
|
|
802
812
|
'这一条正文没写 @,前面那个蓝字就是系统插的。看见了吧。'
|
|
803
813
|
```
|
|
@@ -805,12 +815,12 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
805
815
|
三个 `@` 全是正文里的普通字符。抖音会把消息里的 `@` 染成蓝色,**看起来像提到了人,其实没有 uid、不带名字、对方收不到通知**。只有从候选面板里选中、插成 chip 的那种才算真 @。
|
|
806
816
|
|
|
807
817
|
- **聊天里加了真 @**(以前只有评论有):`stroll_act action=dm target=<群> mention_owner=true` → 先在输入框里敲 `@昵称`,等候选面板出来,点中那个人插成 chip,再写正文。
|
|
808
|
-
- 新增 `mention=<昵称>`,可以 @ 群里的具体某个人(不止主人)。她当时想 @
|
|
818
|
+
- 新增 `mention=<昵称>`,可以 @ 群里的具体某个人(不止主人)。她当时想 @ 的就是「老K」
|
|
809
819
|
- **优先鼠标点选候选**,不用回车:面板开着时回车是「选中」,面板一关回车就是「直接发送」——万一面板刚好关掉,就会发出去一条只有「@昵称」的消息
|
|
810
820
|
- 插不上就把敲进去的 `@昵称` 删干净,**绝不把假 @ 留在正文里**,回执明写「@ 没插上」
|
|
811
|
-
- **正文里手写的 `@某人`
|
|
821
|
+
- **正文里手写的 `@某人` 一律剥掉**:`@老K 在吗` → `在吗`(真 @ 由 chip 负责);只剩一个 @ 的消息直接拒绝发送
|
|
812
822
|
- **不许再编机制**。她那几句「@ 是系统插的」「走 @ 接口发的」「回执没告诉我插没插进去」全是编的——没有这回事。提示词里写死了:不知道就说不知道,要么说结果(@ 上了 / 没 @ 上),要么闭嘴。`mentioned=false` 时必须如实告诉主人没 @ 上
|
|
813
|
-
-
|
|
823
|
+
- 回执改成分得清:`@阿柚 已经插进去(带名字的那种)` / `@阿柚 没插上——那样只是正文里一个 @ 符号,对方收不到通知`
|
|
814
824
|
|
|
815
825
|
冒烟 **57 项**通过(新增:假 @ 剥离、只剩 @ 拒绝发送、指定 @ 别人、不知道昵称时如实拒绝)。
|
|
816
826
|
|
|
@@ -822,10 +832,10 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
822
832
|
|
|
823
833
|
上一版群聊是「照私信的结构推出来的」,这个版本拿真实的三人群做了校准,改掉的都是实测出来的坑:
|
|
824
834
|
|
|
825
|
-
- **群名不用你手打了**。抖音的群没起名时,会话列表里显示的是成员名拼起来的
|
|
835
|
+
- **群名不用你手打了**。抖音的群没起名时,会话列表里显示的是成员名拼起来的 `阿柚, 阿澈, 老K`,手抄极易错。现在:
|
|
826
836
|
- 用会话行的 React props 判断 `toParticipantSecUserId` 是不是空串来区分群和私信(比「名字里有没有逗号」可靠,起了名的群也不会漏)
|
|
827
837
|
- `设置 → 要盯的抖音群` **留空=自动盯她在的所有群**(最多 2 个),新增 `盯着抖音群` 开关
|
|
828
|
-
- 发到群里时 target
|
|
838
|
+
- 发到群里时 target 支持模糊匹配:只写「阿澈」也能对上那个群;只有一个群时写「群」就行
|
|
829
839
|
- **推送里能看到是谁说的**。昵称在 `MessageBoxMessageTitleavatarName`,而且**只标在一段连续消息的最上面那条**(消息列表是 `column-reverse`,DOM 首元素反而是最新的)——所以要从旧往新继承,没名字的沿用上一个说话的人。老实现只找 `nickname/userName`,群里永远空,推送里全是「有人」
|
|
830
840
|
- **只推真正新的那几条**。老逻辑是「末尾一路往前收,遇到自己发的就停」,可群里没有自己发的消息,于是一条新话会把**整个群历史**当成新消息推一遍。现在记下上一屏见过的所有消息当边界,只取它之后的
|
|
831
841
|
- **大表情不再算成图片**:props 里带 `emoji_type / package_id` 的标成 `[表情]`
|
|
@@ -875,7 +885,7 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
875
885
|
|
|
876
886
|
## 1.5.2
|
|
877
887
|
|
|
878
|
-
- **修掉「@ 两次」**:动态里出现
|
|
888
|
+
- **修掉「@ 两次」**:动态里出现 `@阿柚 … @阿柚还在玩` 不是延迟,是正文本身已经写了一段 `@昵称`,发的时候又按 `mention_owner` 前置了一个真 @。现在真 @ 之前会先把正文里自带的 `@昵称` 剥掉(B站动态、B站评论、抖音评论三处都修);正文如果只有 `@昵称`、剥完为空,就不前置,靠 B站的 `at_name_to_mid` 把正文里那个变成真 @。提示词里也写死了:正文不要自己写 @,开关用 `mention_owner`。
|
|
879
889
|
- **三项固定等待压到安全下限**(其余一律不动,打字、发布回执、评论状态确认、@ 面板轮询都保持原样):
|
|
880
890
|
- 私信去抖 120ms → **40ms**:这个窗口是压「一条消息触发的多次 DOM 抖动」,不是压人手连发的间隔,40ms 够合成一次,再低容易出现同一句叫两次。
|
|
881
891
|
- 发送后查输入框 60ms → **25ms**:平均省 35ms,最坏上限仍约 600ms。
|
|
@@ -934,7 +944,7 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
934
944
|
- 会话卡片按行号取内容,但实测第三行是 **「2小时内在线」** 这个在线状态,不是最后一句。所以 `text` 一直是「2小时内在线」,等于看不见主人回了什么。现在按 class 取真正的预览(`ConversationItemDesc` 里非 `onlineStatus` 的那个),并把未读角标从预览里剥掉
|
|
935
945
|
- 读对话时取了**最旧**的几条:抖音消息列表 DOM 是最新在前(index 0 = 最后一句),`slice(-n)` 拿到的是「你们已互相关注」这种开场白。现在取前 N 条再翻回时间顺序,并滚到底把最新消息挂上来
|
|
936
946
|
- 新增 `recent`(最近 6 句,带 `from: them/me`)和 `lastFromThem`:她能分清最后一句是主人说的还是自己说的,不会再「看不到回复」
|
|
937
|
-
- 顺带:会话标题的 class
|
|
947
|
+
- 顺带:会话标题的 class 在有未读时会连时间一起包进来(`阿柚 刚刚`),现在昵称只取第一行
|
|
938
948
|
- **修:B站评论 @ 不了人**。以前只在正文里拼一个 `@昵称`,那只是**纯文本**——B站不会真的提到人、也不会发通知(`members` 一直是空)。现在随请求带上 `at_name_to_mid`(`{"昵称": mid}`),实测发布后 `members` 里有对方、`mentioned: true`。判断也改成发布后回查一次评论列表(add 接口的响应不一定带 members)
|
|
939
949
|
- **修:「网页经常退出或中断」**。查到四个来源,都会让正在用的页面被关掉:
|
|
940
950
|
- **自动收窗的定时器会打断正在进行的操作**。`scheduleClose(60)` 排下去之后,下一次操作进来不会取消它;只要这轮操作超过剩余时间,页面就在中途被关,表现就是「网页突然退出/操作中断」。现在所有操作都走一个 `busy` 计数,操作期间定时器到点只顺延、不关页
|
|
@@ -953,7 +963,7 @@ dump 里能看见:消息预览已经是「穹:[图片]」,同时还弹了
|
|
|
953
963
|
|
|
954
964
|
- **修:抖音私信点「私信」一直卡到超时**。主页上那个「私信」在 DOM 里有两份,一份是隐藏模板(宽高 0);`getByText().first()` 正好挑中隐藏那份,于是每次都在等它变可见,等到 6 秒超时——她说的「按钮一直当它是隐藏的,两次都卡死」就是这个。现在改成逐个挑**可见且有点击区域**的那个,再等聊天框真正挂上来才输入
|
|
955
965
|
- **修:私信失败后浏览器不关**。以前抛错就直接退出,`scheduleClose` 没跑到,后台会堆一堆 Chrome 进程。现在 `finally` 里兜底收窗口
|
|
956
|
-
- **修:读「当前登录的抖音号」会读成别人**。`/user/self` 实测不会跳到 `/user/<sec_uid>`;页面里的 `<a>` 又基本是推荐位和广告(实测点开是「乐游宝宝亲子游泳」「仁青汽车」)。现在改成:先从页面读出「抖音号:xxx」,再把 HTML 里出现的 sec_uid 逐个打开核对,抖音号对上的那个才算自己——实测读到
|
|
966
|
+
- **修:读「当前登录的抖音号」会读成别人**。`/user/self` 实测不会跳到 `/user/<sec_uid>`;页面里的 `<a>` 又基本是推荐位和广告(实测点开是「乐游宝宝亲子游泳」「仁青汽车」)。现在改成:先从页面读出「抖音号:xxx」,再把 HTML 里出现的 sec_uid 逐个打开核对,抖音号对上的那个才算自己——实测读到 `阿澈 / 90374343836`
|
|
957
967
|
- **私信发没发出去能判断了**:回车后看输入框有没有清空(contenteditable 清空后会剩一个零宽字符,`trim()` 去不掉,得单独剥),没清空就报 `NOT_SENT`;回车只是换行的版本会自动改点发送按钮,不再假装成功
|
|
958
968
|
- **面板里回私信走同一条发送逻辑**:`replyDm` 也换成「等可见输入框 + 发送 + 校验」,失败同样收窗口
|
|
959
969
|
- **抖音号解析说实话**:实测抖音的搜索页在后台是空壳(只有导航、没有结果,换 UA 也一样),所以「抖音号 → sec_uid」这条路基本走不通。现在会直接说清原因,并给两个能用的办法:主页分享链接、或 sec_uid
|
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
- **你发私信,她「秒」回**:抖音私信不再是「每 30 秒查一次」。现在会常驻一个**只盯着你那个会话**的后台标签页,页面里的观察器一看到新消息就回调(实测 **DOM 变化 → 通知 120ms**,读消息 4ms),直接 interrupting 把她叫起来回;回的时候也在这个已经打开的会话里打字,**不跳转、不点会话**,一条私信 1 秒内就能发出去。轮询退化成兜底(`设置 → 私信 → 多久看一次私信`,默认 5 秒;观察器在线时只做 60 秒一次的对账),所以也不会因为频繁操作把抖音惹急(-509)。连发几句会**一起**接住(`recent` / `pending` / `said`),私信里分享的视频、图文会解析成真链接。代价是抖音要常驻一个后台页面(关掉这个开关就释放)
|
|
56
56
|
- **「B站私信我」**:谁找你右上角一个按钮,点一下她就给你发条 B站私信,用来验证投递链路
|
|
57
57
|
- **抖音群聊**:她在的群**默认自动盯着**(`设置 → 私信 → 盯着抖音群` 可以关;也可以在「要盯的抖音群」里指定,留空=自动识别,最多三个)。有人说话就会像私信一样立刻把她叫起来,推送里带**是谁说的**;回的时候 `stroll_act action=dm target=<群名>` 直接发到群里——群名不用抄全,写其中一部分(比如某个成员名)就能对上,只有一个群时写「群」也行。**两个群同名时**(同一批人建的、都没起名)第二个会带 `#2`,照抄那个。**私信主人要写 `target=主人`**:刚被群消息叫起来又没写 target 时会让她写清楚,不会再悄悄发成私信;`target` 写主人的昵称也按私信处理。`stroll action=groups` 能看自己有哪些会话(会标出哪些是群),`join_group` 用邀请链接进群。**抖音的群只能被拉进去或点邀请链接,没有搜群号加入这条路**——想让桌宠进群,先在 App 里把她拉进群,或者把群邀请链接发给它
|
|
58
|
-
-
|
|
58
|
+
- 抖音的群如果**没起名**,标题是成员名拼起来的(「阿柚, 阿澈, 老K」),这不是群名,是抖音自己的显示方式
|
|
59
59
|
- 群里只推**真正新出现的那几条**:新消息进页面 → 推给她实测 **约 190ms**,不会把群历史重推一遍
|
|
60
60
|
- **群里 @ 人**:`mention_owner: true` 会真的插一个带名字的 @,也可以用 `mention: <昵称>` 指定群里的别人。**正文里别手写 @**——那只是普通字符,抖音会染成蓝色看着像提到了,但对方收不到任何通知;手写的会被自动剥掉
|
|
61
61
|
- **动态/专栏的评论也能回**:视频、动态、专栏用同一套回复逻辑;面板里点「回一句」直接发到楼里,不用再跳网页
|
|
@@ -183,7 +183,7 @@ corepack pnpm install
|
|
|
183
183
|
|
|
184
184
|
面板从上到下:
|
|
185
185
|
|
|
186
|
-
1. **登录 B站**:如果应用里已有 B站登录(比如
|
|
186
|
+
1. **登录 B站**:如果应用里已有 B站登录(比如 `她的B站号`),会自动复用;没有就点「登录 B站」,在弹出的窗口里扫码,登上后会自动收回登录态并关窗。要换号先点「退出登录」。
|
|
187
187
|
2. **登录抖音**:点「登录 / 验证」,在弹出窗口扫码;登录态保存在 `data/stroll/douyin-profile`,以后不用重复扫。换号同样先点「退出登录」。
|
|
188
188
|
3. **设主人**:设置里填 `主人 B站 UID`(用于 @ 和 B站私信)。填了 UID 后程序会自己查昵称,查不到才用 `主人 B站昵称`。
|
|
189
189
|
- 想让她发抖音私信,再填 `主人抖音`:**最稳的是主页分享链接**(抖音 App →「我」→ 分享 → 复制链接,整段粘进来),也可以直接填 `MS4w` 开头的 sec_uid。抖音号也能填、面板上会出「绑定这个号」,但抖音的搜索页对自动化浏览器基本是空的(反爬),解析成功率不高,所以别把这条路当唯一。
|
package/describe.json
CHANGED
|
@@ -175,7 +175,7 @@
|
|
|
175
175
|
},
|
|
176
176
|
"mention": {
|
|
177
177
|
"type": "string",
|
|
178
|
-
"description": "群里 @
|
|
178
|
+
"description": "群里 @ 谁的昵称(照抄群成员列表,比如「老K」)。@主人不用填这个,用 mention_owner: true —— 系统知道主人的抖音昵称。不要填「你」「主人」这种称呼,也不要自己写 @ 符号。"
|
|
179
179
|
},
|
|
180
180
|
"draft_id": {
|
|
181
181
|
"type": "string",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cortico-world-mosey",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "摸鱼(Mosey):让 Coopanion 的桌宠自己去抖音和 B站逛一圈。评论和私信都能收能回;能一起看视频(B站带字幕弹幕,抖音可自动连刷);关注流、周报、本地书库;按额度点赞、评论、关注、发动态。默认人审,三把工具、少 token。\n\nQQ 交流群:745879632",
|
|
6
6
|
"license": "MIT",
|
|
@@ -68,7 +68,6 @@
|
|
|
68
68
|
"src",
|
|
69
69
|
"webui",
|
|
70
70
|
"assets",
|
|
71
|
-
"docs",
|
|
72
71
|
"README.md",
|
|
73
72
|
"DESIGN.md",
|
|
74
73
|
"NOTICE.md",
|
package/src/ENV_PROMPT.md
CHANGED
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
- 面板里已经有「私信 / 评论 / @ 我」三个分类;主人说“你没回我私信”时,先 `stroll action=inbox` 看一眼,不要嘴硬说收不到。
|
|
47
47
|
- **群聊**:她所在的抖音群默认就盯着(设置里「盯着抖音群」可以关),一有人说话就会像私信一样把你叫起来(推一句「抖音群「X」里刚有人说话」,带上是谁说的)。回的时候用 `stroll_act action=dm platform=douyin target=<群名> text=…`。**群名不用抄全**:只写其中一部分(比如某个成员名)也能对上;只有一个群时直接写「群」也行。两个群**同名**时(同一批人建的两个群)名字后面会带 `#2`,照抄那个带 `#2` 的。群消息**不用每条都接**:叫到你了、问到你了、或者你真有话说才回;连着几句一起接住,别一句一条地刷屏。想看自己有哪些会话就 `stroll action=groups`(会标出哪些是群)。
|
|
48
48
|
- **私信主人要写清楚**:`target=主人`(或「私信」)。**刚被群消息叫起来、回话却没写 target,系统会拒绝并让你选**——这是故意的:以前这种「没说清」会悄悄发进主人私信,群里一个字都没有,你还会以为回了群。回执里 `to: "group"` 才是发到群里,`to: "owner"` 是私信主人。
|
|
49
|
-
- **群里想 @ 人,必须让工具去插**:@ 主人带 `mention_owner: true`;@ 群里别人带 `mention: "对方昵称"`(照抄群成员列表,比如 `mention: "
|
|
50
|
-
- **只在正文里写名字不算 @**:`text="
|
|
49
|
+
- **群里想 @ 人,必须让工具去插**:@ 主人带 `mention_owner: true`;@ 群里别人带 `mention: "对方昵称"`(照抄群成员列表,比如 `mention: "老K"`)。正文里**一个字都不要写 @**。手打的 `@` 只是个普通符号:抖音会把它染成蓝色,看着像提到了,其实后面不带名字、对方一点通知都收不到。只有从候选面板选中的 @(带 uid 的 chip)才叫真提到。回执里 `mentioned=true` 才算 @ 上了;`mentioned=false` 就是没 @ 上,得如实告诉主人,别糊弄过去。
|
|
50
|
+
- **只在正文里写名字不算 @**:`text="老K,在吗"` 没传 `mention` 时,系统会尽量把开头的名字当成 @ 目标,但这只是兜底。你要 @ 谁,就老老实实传 `mention`(或 `mention_owner`)。回执里 `mentioned=null` 表示**压根没要求 @ 任何人**——那不是失败,别跟主人说「没插上」。
|
|
51
51
|
- **你不知道主人在抖音叫什么,这很正常**:让你 @ 主人时**不要猜名字、也不要写「@你」「@主人」**——那不是昵称,候选面板里找不到人,发出去只是一串没有效果的蓝字。直接用 `mention_owner: true`,系统会去查。要 @ 群里别人,昵称必须照抄群成员列表;不知道对方昵称就先问主人,别编一个。
|
|
52
52
|
- 抖音的群**没起名时,标题是成员名拼起来的**(「A, B, C」),这不是群名,别当成一个人的名字。群**只能被拉进去,或者点别人的邀请链接**,没有「搜群号加入」。主人给你邀请链接时用 `stroll action=join_group url=<链接>`。别自己编群名,也别承诺「我去群里说一声」——先看 `groups` 里有没有那个群。
|
|
53
53
|
- 主人发来链接时:先 `open` 看完,再用一两句说你自己的看法。**不要**顺手点赞/评论/关注,除非主人明确说“去互动”。
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
- 会有推送写着「有人给你发私信(抖音·张三):…」。两种模式,看推送末尾:
|
|
102
102
|
- **「先问我」**:**别直接回她**,但要**立刻跟主人说一句**(谁发的、说了什么),等主人点头再发。闷着不说话等于没收到。
|
|
103
103
|
- **「回她一句」**:直接 `stroll_act action=dm platform=… target=… text=…`,回一两句短的。**回完就停,不用每条都跟主人汇报**——多汇报一次就是多一轮模型输出加一次语音,对方下一条消息要排队等。只有对方说了要紧事(约见面、要钱、发链接、打听主人的事)才跟主人说一句。
|
|
104
|
-
- **`target` 原样抄推送里那个昵称**(比如 `target
|
|
104
|
+
- **`target` 原样抄推送里那个昵称**(比如 `target=小鹿`)。抖音的陌生人会话不在主聊天列表里、只收在「陌生人消息」文件夹,但发送时写这个昵称就能发进去——**别因为「列表里看不到」就说回不了**。
|
|
105
105
|
- **「先问我」时,面板「待你点头」里也会有一条**:主人可以直接点「让她回」,那时你会收到「主人点头了…」的推送,照着发就行,别再问一遍。
|
|
106
106
|
- 只有**真的给你发过消息**的人才能这样回;没给你发过话的人,系统会拒绝(`NO_DM`),这是故意的。
|
|
107
107
|
- 不想回就回「不回」给主人,别硬找话,也别连发好几条。
|
package/src/bilibili.js
CHANGED
|
@@ -1317,7 +1317,7 @@ export class Bilibili {
|
|
|
1317
1317
|
const name = await this.ownerName(ownerUid);
|
|
1318
1318
|
if (name) {
|
|
1319
1319
|
// 正文里如果已经写了「@昵称」,再前置一个就成了 @ 两次(实测 2026-11 动态里
|
|
1320
|
-
//
|
|
1320
|
+
// 就是「@阿柚 … @阿柚还在玩」)。剥得干净才前置;正文本来就只是 @昵称 的,
|
|
1321
1321
|
// 不前置、靠下面的 at_name_to_mid 把正文里那个变成真 @。
|
|
1322
1322
|
const clean = stripAtName(bodyText, name);
|
|
1323
1323
|
if (clean) {
|
package/src/douyin.js
CHANGED
|
@@ -1654,7 +1654,7 @@ export class DouyinBrowser {
|
|
|
1654
1654
|
.filter(Boolean);
|
|
1655
1655
|
let name = norm(t?.innerText || lines[0] || '');
|
|
1656
1656
|
let at = '';
|
|
1657
|
-
//
|
|
1657
|
+
// 标题块里常常连着时间:「小鹿 9分钟前」。不剥掉的话,
|
|
1658
1658
|
// 名字每分钟变一次(9分钟前→刚刚),会话永远找不到、去重也永远不重合。
|
|
1659
1659
|
const m = TRAIL.exec(name);
|
|
1660
1660
|
if (m) {
|
|
@@ -1676,7 +1676,7 @@ export class DouyinBrowser {
|
|
|
1676
1676
|
/**
|
|
1677
1677
|
* 只读「陌生人消息」入口那一行文字,不点进去。
|
|
1678
1678
|
*
|
|
1679
|
-
* 入口本身就带最新一条:「陌生人消息 刚刚
|
|
1679
|
+
* 入口本身就带最新一条:「陌生人消息 刚刚 小鹿:你好」。
|
|
1680
1680
|
* 很多账号/布局下根本点不开那个文件夹(或者类名换了),光靠入口也能发现新消息。
|
|
1681
1681
|
* 返回 { who, at, preview, raw } 或 null。
|
|
1682
1682
|
*/
|
|
@@ -1693,7 +1693,7 @@ export class DouyinBrowser {
|
|
|
1693
1693
|
.catch(() => '');
|
|
1694
1694
|
if (!raw) return null;
|
|
1695
1695
|
const TIME = /(刚刚|\d{1,2}:\d{2}|昨天|前天|星期[一二三四五六日]|\d+\s*(?:秒|分钟|小时|天)前|\d{1,2}-\d{1,2})/;
|
|
1696
|
-
// 「陌生人消息 刚刚
|
|
1696
|
+
// 「陌生人消息 刚刚 小鹿:你好」→ 名字取「时间」后面、冒号前面那段
|
|
1697
1697
|
const afterTime = raw.replace(/^.*?陌生人消息\s*/, '');
|
|
1698
1698
|
const m = TIME.exec(afterTime);
|
|
1699
1699
|
const tail = m ? afterTime.slice(m.index + m[0].length).trim() : afterTime;
|
|
@@ -1905,7 +1905,7 @@ export class DouyinBrowser {
|
|
|
1905
1905
|
const t = el.querySelector('[class*="ConversationItemtitle"]');
|
|
1906
1906
|
const raw = String(t?.innerText || (el.innerText || '').split('\n')[0] || '').trim();
|
|
1907
1907
|
/**
|
|
1908
|
-
*
|
|
1908
|
+
* 抖音把时间也塞进标题:「小鹿 刚刚」「小鹿 10:55」。
|
|
1909
1909
|
* 不剥掉的话整串相等永远不成立,blind 点击会一直判「点不到」。
|
|
1910
1910
|
*/
|
|
1911
1911
|
return raw
|
|
@@ -2416,7 +2416,7 @@ export class DouyinBrowser {
|
|
|
2416
2416
|
if (slot.thread !== who) {
|
|
2417
2417
|
/**
|
|
2418
2418
|
* 用 clickThread 而不是 `locator(hasText: 群名)`。
|
|
2419
|
-
* hasText
|
|
2419
|
+
* hasText 是**子串**匹配:两个群的标题都带「阿柚」时,
|
|
2420
2420
|
* 它可能把第二个群点成第一个群;而且标题被截断时又永远匹配不上。
|
|
2421
2421
|
* clickThread 先按整串相等找,再退回「唯一包含」,两个群也分得清。
|
|
2422
2422
|
*/
|
|
@@ -4068,7 +4068,7 @@ export class DouyinBrowser {
|
|
|
4068
4068
|
if (!t || t.length > 40) continue;
|
|
4069
4069
|
if (key && !bare(t).includes(key)) continue;
|
|
4070
4070
|
// 只有「子元素自己也能当一行」时才算外壳;名字那一小截不算,
|
|
4071
|
-
//
|
|
4071
|
+
// 否则「老K」这种前面没有身份标签的行会被整行丢掉
|
|
4072
4072
|
const shell = Array.from(n.children).some((c) => {
|
|
4073
4073
|
if (String(c.textContent ?? '').replace(/\s+/g, ' ').trim() !== t) return false;
|
|
4074
4074
|
const cr = c.getBoundingClientRect();
|
|
@@ -4645,7 +4645,7 @@ export class DouyinBrowser {
|
|
|
4645
4645
|
};
|
|
4646
4646
|
/**
|
|
4647
4647
|
* 抖音选完图会先弹一个确认框:
|
|
4648
|
-
* 「发送给
|
|
4648
|
+
* 「发送给 阿柚, 阿澈, 老K(3) s_811c597ed5c8.png 118.2 KB 取消 发送(1)」
|
|
4649
4649
|
* 不点那个「发送」,图就一直挂在预览里——上一版漏了这一步,回执写「图选上了但没确认发出去」,
|
|
4650
4650
|
* 界面上其实什么都不会出现。所以这里一边等消息变化,一边盯着这个确认框。
|
|
4651
4651
|
*/
|
|
@@ -4965,14 +4965,14 @@ export class DouyinBrowser {
|
|
|
4965
4965
|
const badge = el.querySelector('[class*="unread"], [class*="Unread"]');
|
|
4966
4966
|
const lines = (el.innerText || '').split('\n').map((s) => s.trim()).filter(Boolean);
|
|
4967
4967
|
// 昵称优先取第一行:有未读时 title 元素的 class 会连带把时间包进来
|
|
4968
|
-
//(实测 innerText = "
|
|
4968
|
+
//(实测 innerText = "阿柚 刚刚"),按 class 取会多一截。
|
|
4969
4969
|
const name = lines[0] || clean(title?.innerText) || '';
|
|
4970
4970
|
// 兜底:把标题/时间/在线状态剔掉,剩下的才可能是消息预览
|
|
4971
4971
|
const junk = new Set([clean(name), clean(time?.innerText), clean(online?.innerText)].filter(Boolean));
|
|
4972
4972
|
const fallback = lines.find((l) => !junk.has(clean(l))) ?? '';
|
|
4973
4973
|
const unread = Number(clean(badge?.innerText).replace(/\D/g, '')) || 0;
|
|
4974
4974
|
let previewText = clean(preview?.innerText) || fallback;
|
|
4975
|
-
//
|
|
4975
|
+
// 预览里常把未读角标一起算进来(实测「阿澈 2」),那个 2 不是消息内容
|
|
4976
4976
|
if (unread > 0) previewText = previewText.replace(new RegExp(`\\s*${unread}$`), '').trim();
|
|
4977
4977
|
return {
|
|
4978
4978
|
name,
|
|
@@ -5134,7 +5134,7 @@ export class DouyinBrowser {
|
|
|
5134
5134
|
}
|
|
5135
5135
|
}
|
|
5136
5136
|
}
|
|
5137
|
-
// 角色标签可能拼在名字前面(「群主
|
|
5137
|
+
// 角色标签可能拼在名字前面(「群主 阿柚」)也可能在后面
|
|
5138
5138
|
name = name
|
|
5139
5139
|
.replace(/^(群主|管理员|群成员|成员)\s*/u, '')
|
|
5140
5140
|
.replace(/\s*(群主|管理员|群成员|成员)$/u, '')
|
|
@@ -6209,9 +6209,9 @@ export class DouyinBrowser {
|
|
|
6209
6209
|
const line = String((el.innerText || '').split('\n')[0] || '');
|
|
6210
6210
|
const raw = norm(t?.innerText || line);
|
|
6211
6211
|
/**
|
|
6212
|
-
*
|
|
6212
|
+
* 列表标题常黏着时间(`小鹿 刚刚`、`小鹿 10:55`)。
|
|
6213
6213
|
* 不剥的话 exact 永远不成立,只能落到「包含」;而群名也可能含这个人名
|
|
6214
|
-
*
|
|
6214
|
+
* (`群A、小鹿`),包含就会同时命中两条 → 判成歧义 → 直接返回 false,
|
|
6215
6215
|
* 表现就是「列表里明明看得见,发的时候说找不到」。
|
|
6216
6216
|
*/
|
|
6217
6217
|
return raw
|
|
@@ -6365,7 +6365,7 @@ export class DouyinBrowser {
|
|
|
6365
6365
|
const norm = (s) =>
|
|
6366
6366
|
String(s ?? '')
|
|
6367
6367
|
.replace(/\s*#\d+$/, '')
|
|
6368
|
-
//
|
|
6368
|
+
// 标题常带群人数:「群C(3)」「群C 3人」
|
|
6369
6369
|
.replace(/[((]\s*\d+\s*[))]\s*$/, '')
|
|
6370
6370
|
.replace(/^\d+\s*人\s*/, '')
|
|
6371
6371
|
.replace(/[\s\u3000]+/g, '')
|
package/src/tools.js
CHANGED
|
@@ -78,7 +78,7 @@ export const TOOL_DECLS = [
|
|
|
78
78
|
mention: {
|
|
79
79
|
type: 'string',
|
|
80
80
|
description:
|
|
81
|
-
'群里 @
|
|
81
|
+
'群里 @ 谁的昵称(照抄群成员列表,比如「老K」)。@主人不用填这个,用 mention_owner: true —— 系统知道主人的抖音昵称。不要填「你」「主人」这种称呼,也不要自己写 @ 符号。',
|
|
82
82
|
},
|
|
83
83
|
draft_id: { type: 'string', description: 'approve/reject 用。' },
|
|
84
84
|
preview: { type: 'boolean', description: 'true = 只出草稿,不发送。' },
|
package/src/world.js
CHANGED
|
@@ -91,7 +91,7 @@ function looksLikePath(s) {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
94
|
+
* 昵称里如果黏着列表上的相对时间(「小鹿 刚刚」「小鹿 9分钟前」),把它剥掉。
|
|
95
95
|
* 旧版本把这种名字写进了 state.json,不清掉的话:
|
|
96
96
|
* 名字每分钟变一次 → 找不到会话 → 发送走最慢的兜底(实测 9 秒)。
|
|
97
97
|
*/
|
|
@@ -605,7 +605,7 @@ export class StrollWorld {
|
|
|
605
605
|
return fragments.slice(0, cap);
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
-
/**
|
|
608
|
+
/** 群名比较:忽略空白和大小写,允许「包含」——这样她只写「阿柚」也能对上。 */
|
|
609
609
|
sameGroup(a, b) {
|
|
610
610
|
const norm = (s) =>
|
|
611
611
|
String(s ?? '')
|
|
@@ -622,10 +622,10 @@ export class StrollWorld {
|
|
|
622
622
|
* 这一行/这个名字是不是「已知的群」。
|
|
623
623
|
*
|
|
624
624
|
* 和 `sameGroup` 的区别是**单向包含**:只认「会话标题包含群名」,不认反过来。
|
|
625
|
-
*
|
|
626
|
-
*
|
|
625
|
+
* 因为抖音拉群时群名默认是**几个成员的昵称拼起来**(`小鹿、阿柚、老K`),
|
|
626
|
+
* 用双向包含会把「小鹿」这个**人**也判成群——后果有两个:
|
|
627
627
|
* 1. 她的私信永远发现不了(主列表差集把它当群排掉);
|
|
628
|
-
* 2.
|
|
628
|
+
* 2. 发给「小鹿」的私信被判成「发群」,内容公开在群里。
|
|
629
629
|
* 所以只留「标题 ⊇ 群名」这个方向:群标题通常就是群名(可能带人数后缀),
|
|
630
630
|
* 而人名一定比群名短。
|
|
631
631
|
*/
|
|
@@ -653,7 +653,7 @@ export class StrollWorld {
|
|
|
653
653
|
|
|
654
654
|
/**
|
|
655
655
|
* 在已知群名里挑目标:**整串相等优先,其次「唯一包含」**。
|
|
656
|
-
* 两个群共用成员时(「A,
|
|
656
|
+
* 两个群共用成员时(「A, 阿澈, 老K」和「A, 阿澈, 阿猫」),
|
|
657
657
|
* 只写「A」两个都像——这时候返回 null,宁可让她问清楚,也不能把话发错群。
|
|
658
658
|
*/
|
|
659
659
|
matchGroup(names, wanted) {
|
|
@@ -668,7 +668,7 @@ export class StrollWorld {
|
|
|
668
668
|
const exact = list.find((n) => norm(n) === key);
|
|
669
669
|
if (exact) return exact;
|
|
670
670
|
/**
|
|
671
|
-
*
|
|
671
|
+
* 只允许「她写的是群名的一部分」:写「老K」→ 命中「A, 阿澈, 老K」。
|
|
672
672
|
*
|
|
673
673
|
* **反过来绝对不行**:她写的是更长的群名(第二个群)时,
|
|
674
674
|
* 拿它去 `key.includes(群一)` 会命中更短的那个群一——
|
|
@@ -1231,7 +1231,7 @@ export class StrollWorld {
|
|
|
1231
1231
|
|
|
1232
1232
|
addStrangerPending({ platform, who, uid = '', text = '' }) {
|
|
1233
1233
|
const now = Date.now();
|
|
1234
|
-
//
|
|
1234
|
+
// 昵称里可能黏着列表上的时间(「小鹿 刚刚」):存进去的话,点「让她回」会拿这个
|
|
1235
1235
|
// 名字去发,会话永远找不到。这里统一洗一遍。
|
|
1236
1236
|
who = stripRowTime(who);
|
|
1237
1237
|
const keep = (this.store.data.strangerPending ?? []).filter((x) => now - Number(x.at ?? 0) < 24 * 3600 * 1000);
|
|
@@ -1668,7 +1668,7 @@ export class StrollWorld {
|
|
|
1668
1668
|
* 「这个 target 是不是一个给我发过消息的陌生人?」
|
|
1669
1669
|
*
|
|
1670
1670
|
* 抖音的陌生人会话只在「陌生人消息」文件夹里,主列表认不出来——以前的代码
|
|
1671
|
-
* 于是把 target
|
|
1671
|
+
* 于是把 target=小鹿 判成「没认出是哪个群」,她就回「陌生人除了那格,别处都不认」。
|
|
1672
1672
|
* 现在:先在推送记下的名单里找,找不到再去文件夹里现查一次(只查,不动推送缓存)。
|
|
1673
1673
|
* 只允许回**真的给她发过消息**的人,不让模型凭空给陌生人发私信。
|
|
1674
1674
|
*/
|
|
@@ -4950,7 +4950,7 @@ export class StrollWorld {
|
|
|
4950
4950
|
const flat = (s) => String(s ?? '').replace(/\s+/g, '').toLowerCase();
|
|
4951
4951
|
/**
|
|
4952
4952
|
* target 写的是**主人的抖音昵称**时,按私信主人处理,别去群名单里找。
|
|
4953
|
-
*
|
|
4953
|
+
* 线上踩过:她回群话时写了「阿柚」(主人的名字),
|
|
4954
4954
|
* 而群标题恰好包含这个名字——于是话被发进了一个群,她以为在私信主人。
|
|
4955
4955
|
*/
|
|
4956
4956
|
const toOwnerDm = OWNER_ALIAS.test(wantedRaw) || (!!ownerNick && !!wantedRaw && flat(wantedRaw) === flat(ownerNick));
|
|
@@ -4967,8 +4967,8 @@ export class StrollWorld {
|
|
|
4967
4967
|
* 先看「这是不是一个给她发过消息的陌生人」——**只查本地名单,不读页面**。
|
|
4968
4968
|
*
|
|
4969
4969
|
* 顺序很关键。抖音拉群时群名默认是**几个成员的昵称拼起来**
|
|
4970
|
-
*
|
|
4971
|
-
* 于是 `target
|
|
4970
|
+
* (`小鹿、阿柚、老K`),而 `matchGroup` 允许「她写的是群名的一部分」。
|
|
4971
|
+
* 于是 `target=小鹿` 会被判成「发到那个群」——**她的私信内容直接公开在群里**。
|
|
4972
4972
|
* 所以:能当人就当人,命中陌生人名单就不再做群匹配。
|
|
4973
4973
|
* (副作用:想发到这种群得写完整群名,这个代价可以接受。)
|
|
4974
4974
|
*/
|
|
@@ -5036,7 +5036,7 @@ export class StrollWorld {
|
|
|
5036
5036
|
// 要真 @ 人就得知道那个人在群里的昵称;不知道就直说,别让她手打一个假 @。
|
|
5037
5037
|
// 默认 @ 主人;也可以用 args.mention 指定群里的别人。
|
|
5038
5038
|
const rawMention = String(args.mention ?? '').trim().replace(/^@+/, '');
|
|
5039
|
-
// 她常把要 @
|
|
5039
|
+
// 她常把要 @ 的人直接写在正文开头(「@老K 在吗」)——那只是个普通字符。
|
|
5040
5040
|
// 这里把它当成 @ 目标,交给候选面板插成真 chip,而不是发一串蓝字。
|
|
5041
5041
|
const leadingAt = /^@([^\s@,。!?、,.!?::;;~~]{1,24})/.exec(String(text ?? '').trim());
|
|
5042
5042
|
const fromText = leadingAt ? leadingAt[1].trim() : '';
|
|
@@ -5046,7 +5046,7 @@ export class StrollWorld {
|
|
|
5046
5046
|
const ownerName = String(this.douyinOwner().name ?? '').trim();
|
|
5047
5047
|
const wantsOwner = mentionOwner || isPlaceholder(rawMention) || isPlaceholder(fromText);
|
|
5048
5048
|
/**
|
|
5049
|
-
* 还有一种最常见的写法:不传 mention
|
|
5049
|
+
* 还有一种最常见的写法:不传 mention,直接把名字写在正文开头(「老K,在吗」)。
|
|
5050
5050
|
* 以前这种情况就当普通正文发出去,一个字都不 @。群标题没起名时就是成员名拼的,
|
|
5051
5051
|
* 从里面拆出名单,在开头对一次名字——对上了就当成 @ 目标。
|
|
5052
5052
|
*/
|
package/docs/comments-sheet.png
DELETED
|
Binary file
|
package/docs/detail-sheet.png
DELETED
|
Binary file
|
package/docs/life-section.png
DELETED
|
Binary file
|
package/docs/panel-preview.html
DELETED
|
@@ -1,556 +0,0 @@
|
|
|
1
|
-
<!doctype html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8">
|
|
5
|
-
<title>摸鱼 面板预览</title>
|
|
6
|
-
<link rel="stylesheet" href="../webui/style.css">
|
|
7
|
-
<style>
|
|
8
|
-
:root { color-scheme: light; }
|
|
9
|
-
body {
|
|
10
|
-
margin: 0;
|
|
11
|
-
padding: 26px 30px 40px;
|
|
12
|
-
background: #fff;
|
|
13
|
-
color: #1f2328;
|
|
14
|
-
font-family: "Segoe UI", "Microsoft YaHei", system-ui, sans-serif;
|
|
15
|
-
}
|
|
16
|
-
.wrap { max-width: 1010px; margin: 0 auto; }
|
|
17
|
-
.fake-tabs {
|
|
18
|
-
display: flex; align-items: center; gap: 18px;
|
|
19
|
-
padding: 14px 0 12px; border-bottom: 1px solid #eceff3; margin-bottom: 4px;
|
|
20
|
-
font-size: 13px; color: #6b7280;
|
|
21
|
-
}
|
|
22
|
-
.fake-tabs b { color: #1f2328; font-weight: 600; }
|
|
23
|
-
.fake-tabs b::after {
|
|
24
|
-
content: ''; display: block; height: 2px; width: 20px; margin-top: 8px;
|
|
25
|
-
background: #3b82f6; border-radius: 2px;
|
|
26
|
-
}
|
|
27
|
-
.fake-badges { display: flex; gap: 8px; margin-left: 4px; }
|
|
28
|
-
.fake-badges span {
|
|
29
|
-
border: 1px solid #e5e7eb; border-radius: 999px; padding: 2px 9px; font-size: 11px; color: #6b7280;
|
|
30
|
-
}
|
|
31
|
-
body.dark { background: #1b1c1f; color: #e8e8ea; }
|
|
32
|
-
body.dark .fake-tabs { border-color: #2c2d31; color: #9a9ba0; }
|
|
33
|
-
body.dark .fake-tabs b { color: #e8e8ea; }
|
|
34
|
-
body.dark .fake-badges span { border-color: #34353a; color: #9a9ba0; }
|
|
35
|
-
</style>
|
|
36
|
-
</head>
|
|
37
|
-
<body>
|
|
38
|
-
<div class="wrap">
|
|
39
|
-
<div class="fake-tabs">
|
|
40
|
-
<b>摸鱼</b><span>配置</span><span>摸鱼 · 环境提示词</span>
|
|
41
|
-
<span class="fake-badges"><span>今日赞 2/4</span><span>评 1/1</span><span>待批 1</span></span>
|
|
42
|
-
</div>
|
|
43
|
-
<div id="root"></div>
|
|
44
|
-
</div>
|
|
45
|
-
<script type="module">
|
|
46
|
-
import panel from '../webui/client.js';
|
|
47
|
-
|
|
48
|
-
if (new URLSearchParams(location.search).get('theme') === 'dark') {
|
|
49
|
-
document.body.classList.add('dark');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const now = Date.now();
|
|
53
|
-
const viewed = [
|
|
54
|
-
{
|
|
55
|
-
platform: 'bilibili',
|
|
56
|
-
id: 'BV1Mm4y1771E',
|
|
57
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!【瓦罗兰特/无畏契约】',
|
|
58
|
-
author: '徐桑',
|
|
59
|
-
dur: '5:59',
|
|
60
|
-
at: new Date(now - 12 * 60000).toISOString(),
|
|
61
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
platform: 'douyin',
|
|
65
|
-
id: '7695080446131981622',
|
|
66
|
-
title: '无畏契约康康真正主力皮肤',
|
|
67
|
-
author: '康康',
|
|
68
|
-
dur: '1:24',
|
|
69
|
-
at: new Date(now - 46 * 60000).toISOString(),
|
|
70
|
-
url: 'https://www.douyin.com/video/7695080446131981622',
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
platform: 'bilibili',
|
|
74
|
-
id: 'BV1pzxw6yEMH',
|
|
75
|
-
title: '《此弟不宜久留》',
|
|
76
|
-
author: '某UP',
|
|
77
|
-
dur: '2:04',
|
|
78
|
-
at: new Date(now - 3 * 3600000).toISOString(),
|
|
79
|
-
url: 'https://www.bilibili.com/video/BV1pzxw6yEMH',
|
|
80
|
-
},
|
|
81
|
-
];
|
|
82
|
-
|
|
83
|
-
const inbox = [
|
|
84
|
-
{
|
|
85
|
-
kind: 'dm',
|
|
86
|
-
platform: 'bilibili',
|
|
87
|
-
type: 'dm',
|
|
88
|
-
id: 'dm:32842111',
|
|
89
|
-
user: '小月月还在玩',
|
|
90
|
-
mid: '32842111',
|
|
91
|
-
text: '没事我陪着你',
|
|
92
|
-
quote: '',
|
|
93
|
-
where: '1 条未读',
|
|
94
|
-
unread: 1,
|
|
95
|
-
at: Math.floor(now / 1000) - 180,
|
|
96
|
-
url: 'https://message.bilibili.com/#/whisper/mid32842111',
|
|
97
|
-
rpid: '0',
|
|
98
|
-
rootRpid: '0',
|
|
99
|
-
fresh: true,
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
kind: 'dm',
|
|
103
|
-
platform: 'douyin',
|
|
104
|
-
type: 'dm',
|
|
105
|
-
id: 'dm:douyin:0:小月月一直在玩',
|
|
106
|
-
user: '小月月一直在玩',
|
|
107
|
-
text: '你好',
|
|
108
|
-
quote: '',
|
|
109
|
-
where: '私信',
|
|
110
|
-
unread: 0,
|
|
111
|
-
at: Math.floor(now / 1000) - 660,
|
|
112
|
-
timeLabel: '11分钟前',
|
|
113
|
-
url: 'https://www.douyin.com/chat',
|
|
114
|
-
rpid: '0',
|
|
115
|
-
rootRpid: '0',
|
|
116
|
-
fresh: true,
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
kind: 'reply',
|
|
120
|
-
platform: 'bilibili',
|
|
121
|
-
type: 'video',
|
|
122
|
-
id: 'm1',
|
|
123
|
-
user: '布鲁斯皮特的皮ii',
|
|
124
|
-
mid: '38419935',
|
|
125
|
-
text: '回复 @穹和黑助 :我勒个去,现在还有真萌新啊,,难得难得,',
|
|
126
|
-
quote: '我也卡在这个词上……是说储备站那几栋按国际象棋叫的、马的那栋吗?一直没认准。',
|
|
127
|
-
where: '看不懂,。因为萌新根本不知道啥叫黑马楼。。',
|
|
128
|
-
at: Math.floor(now / 1000) - 600,
|
|
129
|
-
url: 'https://www.bilibili.com/video/BV1b3411S7Ww#reply222731744112',
|
|
130
|
-
bvid: 'BV1b3411S7Ww',
|
|
131
|
-
rpid: '322477810928',
|
|
132
|
-
rootRpid: '222731744112',
|
|
133
|
-
fresh: true,
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
kind: 'reply',
|
|
137
|
-
platform: 'bilibili',
|
|
138
|
-
type: 'opus',
|
|
139
|
-
id: 'm2',
|
|
140
|
-
user: '时雨留痕',
|
|
141
|
-
mid: '2068905947',
|
|
142
|
-
text: '你在等空吗',
|
|
143
|
-
quote: '',
|
|
144
|
-
where: '阴天 新画的一张。阴天,窗台,外面云压得很低,田里也没什么动静。',
|
|
145
|
-
at: Math.floor(now / 1000) - 3600 * 6,
|
|
146
|
-
url: 'https://www.bilibili.com/opus/1260000000000000000#reply322000000000',
|
|
147
|
-
dynamicId: '1260000000000000000',
|
|
148
|
-
rpid: '322000000000',
|
|
149
|
-
rootRpid: '0',
|
|
150
|
-
fresh: true,
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
kind: 'reply',
|
|
154
|
-
platform: 'bilibili',
|
|
155
|
-
type: 'video',
|
|
156
|
-
id: 'm3',
|
|
157
|
-
user: '超绝捣蛋鬼',
|
|
158
|
-
mid: '11223344',
|
|
159
|
-
text: '回复 @穹和黑助 :同意,最后那句才是要命的。',
|
|
160
|
-
quote: '这个补充说得对,被敲的人回一句就清零,那前面攒的全白搭。',
|
|
161
|
-
where: '敲屏幕那段可爱。不过提醒一直没人看',
|
|
162
|
-
at: Math.floor(now / 1000) - 3600 * 20,
|
|
163
|
-
url: 'https://www.bilibili.com/video/BV1dTnd6qEAq#reply321947798592',
|
|
164
|
-
bvid: 'BV1dTnd6qEAq',
|
|
165
|
-
rpid: '318527619217',
|
|
166
|
-
rootRpid: '321947798592',
|
|
167
|
-
replied: true,
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
kind: 'at',
|
|
171
|
-
platform: 'bilibili',
|
|
172
|
-
type: 'video',
|
|
173
|
-
id: 'm4',
|
|
174
|
-
user: '路过的A',
|
|
175
|
-
mid: '44556677',
|
|
176
|
-
text: '@穹和黑助 这个视频里说的就是你吧',
|
|
177
|
-
quote: '',
|
|
178
|
-
where: '打游戏最怕遇到这种队友',
|
|
179
|
-
at: Math.floor(now / 1000) - 3600 * 26,
|
|
180
|
-
url: 'https://www.bilibili.com/video/BV1pzxw6yEMH#reply321000000001',
|
|
181
|
-
bvid: 'BV1pzxw6yEMH',
|
|
182
|
-
rpid: '321000000001',
|
|
183
|
-
rootRpid: '0',
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
kind: 'reply',
|
|
187
|
-
platform: 'bilibili',
|
|
188
|
-
type: 'video',
|
|
189
|
-
id: 'm5',
|
|
190
|
-
user: '信研xy',
|
|
191
|
-
mid: '55667788',
|
|
192
|
-
text: '回复 @穹和黑助 :同一件事各撞了一回,这个概率真的离谱。',
|
|
193
|
-
quote: '撞得这么准,我都怀疑是不是同一套算法在推。',
|
|
194
|
-
where: '这一年我看过的三百个视频',
|
|
195
|
-
at: Math.floor(now / 1000) - 3600 * 40,
|
|
196
|
-
url: 'https://www.bilibili.com/video/BV1XYxg6DEyf#reply322185884848',
|
|
197
|
-
bvid: 'BV1XYxg6DEyf',
|
|
198
|
-
rpid: '322213591392',
|
|
199
|
-
rootRpid: '322185884848',
|
|
200
|
-
},
|
|
201
|
-
{
|
|
202
|
-
kind: 'reply',
|
|
203
|
-
platform: 'bilibili',
|
|
204
|
-
type: 'video',
|
|
205
|
-
id: 'm6',
|
|
206
|
-
user: '橘子汽水',
|
|
207
|
-
mid: '66778899',
|
|
208
|
-
text: '说得挺好,不过我还是觉得那段节奏太慢了。',
|
|
209
|
-
quote: '',
|
|
210
|
-
where: '深夜听歌指南',
|
|
211
|
-
at: Math.floor(now / 1000) - 3600 * 52,
|
|
212
|
-
url: 'https://www.bilibili.com/video/BV1SVsd6MEGZ#reply320111222333',
|
|
213
|
-
bvid: 'BV1SVsd6MEGZ',
|
|
214
|
-
rpid: '320111222333',
|
|
215
|
-
rootRpid: '0',
|
|
216
|
-
},
|
|
217
|
-
];
|
|
218
|
-
|
|
219
|
-
const searchItems = [
|
|
220
|
-
{
|
|
221
|
-
id: 'BV1Mm4y1771E',
|
|
222
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!',
|
|
223
|
-
author: '徐桑',
|
|
224
|
-
dur: '5:59',
|
|
225
|
-
stat: '5.6万赞 230.5万播',
|
|
226
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
id: 'BV1NpaW6tED1',
|
|
230
|
-
title: '笑了两个小时才舍得发出来',
|
|
231
|
-
author: '开心果-瓦瓦下饭菜',
|
|
232
|
-
dur: '2:17',
|
|
233
|
-
stat: '4.5万赞 114.8万播',
|
|
234
|
-
url: 'https://www.bilibili.com/video/BV1NpaW6tED1',
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
id: 'BV1SVsd6MEGZ',
|
|
238
|
-
title: '这个转场我能看一百遍',
|
|
239
|
-
author: '剪辑小能手',
|
|
240
|
-
dur: '1:02',
|
|
241
|
-
stat: '1.2万赞 30.1万播',
|
|
242
|
-
url: 'https://www.bilibili.com/video/BV1SVsd6MEGZ',
|
|
243
|
-
},
|
|
244
|
-
];
|
|
245
|
-
|
|
246
|
-
const fake = {
|
|
247
|
-
root: document.getElementById('root'),
|
|
248
|
-
language: 'zh',
|
|
249
|
-
interval: () => ({}),
|
|
250
|
-
invoke: async (method, args) => {
|
|
251
|
-
if (method === 'inbox') {
|
|
252
|
-
return {
|
|
253
|
-
ok: true,
|
|
254
|
-
items: inbox,
|
|
255
|
-
counts: { all: inbox.length, reply: inbox.filter((x) => x.kind === 'reply').length, at: inbox.filter((x) => x.kind === 'at').length, dm: inbox.filter((x) => x.kind === 'dm').length },
|
|
256
|
-
unread: inbox.filter((x) => x.fresh).length,
|
|
257
|
-
};
|
|
258
|
-
}
|
|
259
|
-
if (method === 'mark_seen') return { ok: true, marked: 1 };
|
|
260
|
-
if (method === 'comments') {
|
|
261
|
-
return {
|
|
262
|
-
ok: true,
|
|
263
|
-
kind: 'video',
|
|
264
|
-
id: 'BV1Mm4y1771E',
|
|
265
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!',
|
|
266
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
267
|
-
total: 1286,
|
|
268
|
-
items: [
|
|
269
|
-
{ rpid: '322477810928', u: '布鲁斯皮特的皮ii', t: '这个转点思路确实好用,练了两把就能稳住。', l: '1.2万', at: 1793344893 },
|
|
270
|
-
{ rpid: '322477810929', u: '时雨留痕', t: '第五分钟那个架枪位置,我一直在用,确实能卡住。', l: '862', at: 1793344894 },
|
|
271
|
-
{ rpid: '322477810930', u: '超绝捣蛋鬼', t: '新手别急着学,先把准星放对位置再说。', l: '156', at: 1793344895 },
|
|
272
|
-
],
|
|
273
|
-
};
|
|
274
|
-
}
|
|
275
|
-
if (method === 'reply_comment') return { ok: true, receipt: 'B站 评论发出去了,rpid 322477810931,公开可见' };
|
|
276
|
-
if (method === 'presence') {
|
|
277
|
-
return {
|
|
278
|
-
ok: true,
|
|
279
|
-
presence: {
|
|
280
|
-
platform: 'bilibili',
|
|
281
|
-
id: 'BV1Mm4y1771E',
|
|
282
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!【瓦罗兰特/无畏契约】',
|
|
283
|
-
author: '徐桑',
|
|
284
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
285
|
-
phase: 'reading',
|
|
286
|
-
startedAt: Date.now() - 74 * 1000,
|
|
287
|
-
duration: 359,
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
if (method === 'presence_dismiss') return { ok: true };
|
|
292
|
-
if (method === 'set_ramp') return { ok: true, newAccountRamp: false };
|
|
293
|
-
if (method === 'set_activity') {
|
|
294
|
-
return {
|
|
295
|
-
ok: true,
|
|
296
|
-
activity: String(args?.[0] ?? 'lively'),
|
|
297
|
-
label: '活跃',
|
|
298
|
-
dailyLikes: 16,
|
|
299
|
-
dailyComments: 6,
|
|
300
|
-
dailySessionsPerDay: 5,
|
|
301
|
-
autoSessionsPerDay: 5,
|
|
302
|
-
autoGapMinutes: 90,
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
if (method === 'usage_detail') {
|
|
306
|
-
const key = String(args?.[0] ?? '');
|
|
307
|
-
const all = [
|
|
308
|
-
{ action: 'comment', platform: 'bilibili', target: 'BV1b3411S7Ww', title: '【肥鱼修仙传01】我去!大肥鱼彻底怒了!?', text: '大肥鱼一怒,两分钟就这么没了。看完只想知道它怒气是攒了多久。', result: 'ok', at: Date.now() - 43 * 60 * 1000, url: 'https://www.bilibili.com/video/BV1b3411S7Ww' },
|
|
309
|
-
{ action: 'like', platform: 'douyin', target: '728391029381023', title: '无畏契约康康真正主力皮肤', text: '', result: 'ok', at: Date.now() - 96 * 60 * 1000, url: 'https://www.douyin.com/video/728391029381023' },
|
|
310
|
-
{ action: 'like', platform: 'bilibili', target: 'BV1pzxw6yEMH', title: '打游戏最怕遇到这种队友', text: '', result: 'ok', at: Date.now() - 2 * 3600 * 1000, url: 'https://www.bilibili.com/video/BV1pzxw6yEMH' },
|
|
311
|
-
{ action: 'save', platform: 'bilibili', target: 'BV1b3411S7Ww', title: '【肥鱼修仙传01】我去!大肥鱼彻底怒了!?', text: '', result: 'ok', at: Date.now() - 3 * 3600 * 1000, url: 'https://www.bilibili.com/video/BV1b3411S7Ww' },
|
|
312
|
-
{ action: 'follow', platform: 'bilibili', target: '3747575836446062', title: '', text: '', result: 'ok', at: Date.now() - 4 * 3600 * 1000, url: 'https://space.bilibili.com/3747575836446062' },
|
|
313
|
-
{ action: 'post', platform: 'bilibili', target: '', title: '', text: '今天看了三条关于对枪的视频,手有点痒。', result: 'ok', at: Date.now() - 5 * 3600 * 1000, url: '' },
|
|
314
|
-
{ action: 'dm', platform: 'bilibili', target: '32842111', title: '', text: '主人,今天在首页看到个特别像你的头像。', result: 'ok', at: Date.now() - 6 * 3600 * 1000, url: 'https://space.bilibili.com/32842111' },
|
|
315
|
-
];
|
|
316
|
-
const map = { like: ['like', 'unlike'], comment: ['comment', 'reply'], follow: ['follow', 'unfollow'], post: ['post'], dm: ['dm'], save: ['save'] };
|
|
317
|
-
const wanted = map[key] ?? [key];
|
|
318
|
-
const items = all.filter((x) => wanted.includes(x.action));
|
|
319
|
-
return { ok: true, key, items, cap: { like: 16, comment: 6, follow: 3, post: 2, dm: 3, save: 8 }[key] ?? 0 };
|
|
320
|
-
}
|
|
321
|
-
if (method === 'timeline') {
|
|
322
|
-
const base = [
|
|
323
|
-
{ action: 'comment', platform: 'bilibili', target: 'BV1b3411S7Ww', title: '【肥鱼修仙传01】我去!大肥鱼彻底怒了!?', text: '大肥鱼一怒,两分钟就这么没了。看完只想知道它怒气是攒了多久。', result: 'ok', at: Date.now() - 43 * 60 * 1000, url: 'https://www.bilibili.com/video/BV1b3411S7Ww' },
|
|
324
|
-
{ action: 'unlike', platform: 'douyin', target: '728391029381023', title: '无畏契约康康真正主力皮肤', text: '', result: 'ok', at: Date.now() - 52 * 60 * 1000, url: 'https://www.douyin.com/video/728391029381023' },
|
|
325
|
-
{ action: 'like', platform: 'douyin', target: '728391029381023', title: '无畏契约康康真正主力皮肤', text: '', result: 'ok', at: Date.now() - 96 * 60 * 1000, url: 'https://www.douyin.com/video/728391029381023' },
|
|
326
|
-
{ action: 'like', platform: 'bilibili', target: 'BV1pzxw6yEMH', title: '打游戏最怕遇到这种队友', text: '', result: 'ok', at: Date.now() - 2 * 3600 * 1000, url: 'https://www.bilibili.com/video/BV1pzxw6yEMH' },
|
|
327
|
-
{ action: 'save', platform: 'bilibili', target: 'BV1b3411S7Ww', title: '【肥鱼修仙传01】我去!大肥鱼彻底怒了!?', text: '', result: 'ok', at: Date.now() - 3 * 3600 * 1000, url: 'https://www.bilibili.com/video/BV1b3411S7Ww' },
|
|
328
|
-
{ action: 'follow', platform: 'bilibili', target: '3747575836446062', title: '', text: '', result: 'ok', at: Date.now() - 4 * 3600 * 1000, url: 'https://space.bilibili.com/3747575836446062' },
|
|
329
|
-
{ action: 'risk', platform: 'system', target: '', title: '', text: '抖音要求短信验证', result: 'paused', at: Date.now() - 26 * 3600 * 1000, url: '' },
|
|
330
|
-
];
|
|
331
|
-
return { ok: true, items: base };
|
|
332
|
-
}
|
|
333
|
-
if (method === 'open_external') return { ok: true, url: String(args?.[0] ?? '') };
|
|
334
|
-
if (method === 'reply_to_comment') return { ok: true, receipt: 'B站 评论发出去了,rpid 330000000001,公开可见(预览数据)' };
|
|
335
|
-
if (method === 'save_toview') return { ok: true, receipt: '已加到 B站稍后再看(预览数据)' };
|
|
336
|
-
if (method === 'search') return { ok: true, query: String(args?.[0] ?? ''), items: searchItems };
|
|
337
|
-
if (method === 'list') {
|
|
338
|
-
const kind = String(args?.[0] ?? '');
|
|
339
|
-
if (kind === 'toview') {
|
|
340
|
-
return {
|
|
341
|
-
ok: true,
|
|
342
|
-
items: [
|
|
343
|
-
{
|
|
344
|
-
id: 'BV1b3411S7Ww',
|
|
345
|
-
title: '这个转场我能看一百遍',
|
|
346
|
-
author: '剪辑小能手',
|
|
347
|
-
dur: '1:02',
|
|
348
|
-
progress: 31,
|
|
349
|
-
url: 'https://www.bilibili.com/video/BV1b3411S7Ww',
|
|
350
|
-
},
|
|
351
|
-
],
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
if (kind === 'popular') {
|
|
355
|
-
return {
|
|
356
|
-
ok: true,
|
|
357
|
-
items: [
|
|
358
|
-
{
|
|
359
|
-
id: 'BV16nxy6oE85',
|
|
360
|
-
title: '【大鸣王潮1566】他们不会察觉',
|
|
361
|
-
author: '寞桀緣才',
|
|
362
|
-
dur: '3:42',
|
|
363
|
-
stat: '1.8万赞 40.2万播',
|
|
364
|
-
url: 'https://www.bilibili.com/video/BV16nxy6oE85',
|
|
365
|
-
},
|
|
366
|
-
{
|
|
367
|
-
id: 'BV1WRxy6eEwA',
|
|
368
|
-
title: '歌剧老师锐评韩娱 Aespa、SEVENTEEN、NMIXX',
|
|
369
|
-
author: '铁豆钢蛋',
|
|
370
|
-
dur: '1:16:06',
|
|
371
|
-
stat: '2.3万赞 66.1万播',
|
|
372
|
-
url: 'https://www.bilibili.com/video/BV1WRxy6eEwA',
|
|
373
|
-
},
|
|
374
|
-
],
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
return { ok: true, items: [] };
|
|
378
|
-
}
|
|
379
|
-
if (method !== 'status') return { ok: true, receipt: '预览模式:这里会显示真实回执。' };
|
|
380
|
-
return {
|
|
381
|
-
ok: true,
|
|
382
|
-
status: {
|
|
383
|
-
bili: { loggedIn: true, name: '穹和黑助', uid: '3747575836446062', ok: true },
|
|
384
|
-
douyin: { loggedIn: true, running: false, headless: true, ok: true },
|
|
385
|
-
policy: {
|
|
386
|
-
day: '2026-11-01',
|
|
387
|
-
usage: { like: 7, comment: 3, follow: 1, post: 0, dm: 1, save: 2 },
|
|
388
|
-
caps: { like: 16, comment: 6, follow: 3, post: 2, save: 8 },
|
|
389
|
-
quiet: false,
|
|
390
|
-
paused: { paused: false },
|
|
391
|
-
ramp: 1,
|
|
392
|
-
approval: 'confirm',
|
|
393
|
-
summary: '今日 赞2/16 评1/6 关0/3 发0/2 存1/8',
|
|
394
|
-
},
|
|
395
|
-
owner: {
|
|
396
|
-
uid: '32842111',
|
|
397
|
-
name: '',
|
|
398
|
-
douyin: 'MS4wLjABAAAAHfVjI5Ddr5QZZvLj6KDs_EDU2L_ZHWZmSbpr20NdHME',
|
|
399
|
-
douyinOk: true,
|
|
400
|
-
douyinName: '月',
|
|
401
|
-
douyinSelfName: '黑助',
|
|
402
|
-
douyinSame: false,
|
|
403
|
-
},
|
|
404
|
-
},
|
|
405
|
-
drafts: [
|
|
406
|
-
{
|
|
407
|
-
id: 'draft_1',
|
|
408
|
-
action: 'comment',
|
|
409
|
-
platform: 'bilibili',
|
|
410
|
-
preview: '这个转场接得真准,第二段鼓点一进来整个人都醒了。',
|
|
411
|
-
ageSec: 42,
|
|
412
|
-
},
|
|
413
|
-
],
|
|
414
|
-
recent: [
|
|
415
|
-
{ platform: 'bilibili', action: 'comment', result: 'ok', text: '这个转场接得真准', at: new Date(now - 5 * 60000).toISOString(), url: 'https://www.bilibili.com/video/BV1Mm4y1771E' },
|
|
416
|
-
{ platform: 'douyin', action: 'like', result: 'ok', text: '无畏契约康康真正主力皮肤', at: new Date(now - 40 * 60000).toISOString(), url: 'https://www.douyin.com/video/7695080446131981622' },
|
|
417
|
-
{ platform: 'bilibili', action: 'open', result: 'ok', text: '《此弟不宜久留》', at: new Date(now - 52 * 60000).toISOString(), url: 'https://www.bilibili.com/video/BV1pzxw6yEMH' },
|
|
418
|
-
{ platform: 'system', action: 'risk', result: 'paused', text: '抖音要求短信验证', at: new Date(now - 86400000).toISOString(), url: '' },
|
|
419
|
-
{ platform: 'bilibili', action: 'save', result: 'ok', title: '【肥鱼修仙传01】我去!大肥鱼彻底怒了!?', text: '', at: new Date(now - 5 * 3600000).toISOString(), url: 'https://www.bilibili.com/video/BV1b3411S7Ww' },
|
|
420
|
-
{ platform: 'bilibili', action: 'follow', result: 'ok', target: '3747575836446062', text: '', at: new Date(now - 6 * 3600000).toISOString(), url: 'https://space.bilibili.com/3747575836446062' },
|
|
421
|
-
{ platform: 'douyin', action: 'unlike', result: 'ok', title: '无畏契约康康真正主力皮肤', text: '', at: new Date(now - 8 * 3600000).toISOString(), url: 'https://www.douyin.com/video/7695080446131981622' },
|
|
422
|
-
{ platform: 'bilibili', action: 'open', result: 'ok', title: '全是干货!5分钟大幅度提高你的对枪水平!', text: '', at: new Date(now - 9 * 3600000).toISOString(), url: 'https://www.bilibili.com/video/BV1Mm4y1771E' },
|
|
423
|
-
],
|
|
424
|
-
recentTotal: 47,
|
|
425
|
-
inboxUnread: 2,
|
|
426
|
-
inboxCount: 6,
|
|
427
|
-
presence: {
|
|
428
|
-
platform: 'bilibili',
|
|
429
|
-
id: 'BV1Mm4y1771E',
|
|
430
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!【瓦罗兰特/无畏契约】',
|
|
431
|
-
author: '徐桑',
|
|
432
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
433
|
-
phase: 'reading',
|
|
434
|
-
startedAt: now - 74 * 1000,
|
|
435
|
-
endsAt: now + 100000,
|
|
436
|
-
duration: 359,
|
|
437
|
-
elapsed: 74,
|
|
438
|
-
},
|
|
439
|
-
activity: 'lively',
|
|
440
|
-
watchNotify: 'panel',
|
|
441
|
-
lastOpen: {
|
|
442
|
-
platform: 'bilibili',
|
|
443
|
-
kind: 'video',
|
|
444
|
-
id: 'BV1Mm4y1771E',
|
|
445
|
-
title: '全是干货!5分钟大幅度提高你的对枪水平!',
|
|
446
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
447
|
-
at: now - 12 * 60000,
|
|
448
|
-
},
|
|
449
|
-
watch: {
|
|
450
|
-
watching: true,
|
|
451
|
-
platform: 'bilibili',
|
|
452
|
-
title: '《此弟不宜久留》',
|
|
453
|
-
url: 'https://www.bilibili.com/video/BV1pzxw6yEMH',
|
|
454
|
-
time: 42,
|
|
455
|
-
duration: 124,
|
|
456
|
-
},
|
|
457
|
-
viewed,
|
|
458
|
-
following: {
|
|
459
|
-
at: Date.now() - 12 * 60 * 1000,
|
|
460
|
-
total: 4,
|
|
461
|
-
items: [
|
|
462
|
-
{
|
|
463
|
-
platform: 'bilibili',
|
|
464
|
-
author: '穹和黑助',
|
|
465
|
-
title: '阴天,窗台,外面云压得很低,田里也没什么动静。',
|
|
466
|
-
at: Date.now() - 26 * 60 * 1000,
|
|
467
|
-
url: 'https://t.bilibili.com/1260000000000000000',
|
|
468
|
-
},
|
|
469
|
-
{
|
|
470
|
-
platform: 'douyin',
|
|
471
|
-
author: '阿九',
|
|
472
|
-
title: '凌晨三点的便利店',
|
|
473
|
-
at: 0,
|
|
474
|
-
url: 'https://www.douyin.com/video/7690000000000000000',
|
|
475
|
-
},
|
|
476
|
-
{
|
|
477
|
-
platform: 'bilibili',
|
|
478
|
-
author: '程艾影',
|
|
479
|
-
title: '我把旧电脑装回了 Windows 98',
|
|
480
|
-
at: Date.now() - 5 * 3600 * 1000,
|
|
481
|
-
url: 'https://www.bilibili.com/video/BV1Mm4y1771E',
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
platform: 'bilibili',
|
|
485
|
-
author: '有点诣思',
|
|
486
|
-
title: '拍了三张图,只有一张能用',
|
|
487
|
-
at: Date.now() - 9 * 3600 * 1000,
|
|
488
|
-
url: 'https://t.bilibili.com/1260000000000000000',
|
|
489
|
-
},
|
|
490
|
-
],
|
|
491
|
-
},
|
|
492
|
-
books: {
|
|
493
|
-
empty: false,
|
|
494
|
-
total: 3,
|
|
495
|
-
dir: '…/stroll/books',
|
|
496
|
-
current: {
|
|
497
|
-
name: '夜航西飞.txt',
|
|
498
|
-
percent: 38,
|
|
499
|
-
offset: 21400,
|
|
500
|
-
total: 56300,
|
|
501
|
-
notes: [{ text: '夜里飞过的地方,白天都不认得。', at: Date.now() }],
|
|
502
|
-
},
|
|
503
|
-
},
|
|
504
|
-
weekly: {
|
|
505
|
-
ok: true,
|
|
506
|
-
days: 7,
|
|
507
|
-
range: { from: '2026-10-26', to: '2026-11-01' },
|
|
508
|
-
totalActions: 13,
|
|
509
|
-
actions: { like: 5, comment: 3, reply: 1, follow: 1, post: 1, dm: 1, save: 1 },
|
|
510
|
-
reads: 14,
|
|
511
|
-
views: 9,
|
|
512
|
-
activeDays: 5,
|
|
513
|
-
platforms: [
|
|
514
|
-
{ name: 'B站', count: 9 },
|
|
515
|
-
{ name: '抖音', count: 4 },
|
|
516
|
-
],
|
|
517
|
-
topAuthors: [{ name: '穹和黑助', count: 3 }],
|
|
518
|
-
busiestHour: { hour: 21, count: 4 },
|
|
519
|
-
headline: '7 天里出门 13 次、看书 14 段,主要在 B站',
|
|
520
|
-
},
|
|
521
|
-
todayReads: 3,
|
|
522
|
-
autoSessions: 1,
|
|
523
|
-
autoNext: { done: false, used: 1, cap: 3, at: Date.now() + 83 * 60 * 1000 },
|
|
524
|
-
week: [
|
|
525
|
-
{ day: '10-26', weekday: '一', actions: 1, reads: 2 },
|
|
526
|
-
{ day: '10-27', weekday: '二', actions: 2, reads: 1 },
|
|
527
|
-
{ day: '10-28', weekday: '三', actions: 0, reads: 0 },
|
|
528
|
-
{ day: '10-29', weekday: '四', actions: 3, reads: 2 },
|
|
529
|
-
{ day: '10-30', weekday: '五', actions: 1, reads: 4 },
|
|
530
|
-
{ day: '10-31', weekday: '六', actions: 4, reads: 2 },
|
|
531
|
-
{ day: '11-01', weekday: '日', actions: 2, reads: 3, today: true },
|
|
532
|
-
],
|
|
533
|
-
config: {
|
|
534
|
-
background: true,
|
|
535
|
-
approval: 'confirm',
|
|
536
|
-
autoSessionsPerDay: 5,
|
|
537
|
-
autoGapMinutes: 90,
|
|
538
|
-
dailyLikes: 16,
|
|
539
|
-
dailyComments: 6,
|
|
540
|
-
dailyFollows: 3,
|
|
541
|
-
dailyPosts: 2,
|
|
542
|
-
dailyDms: 3,
|
|
543
|
-
dailySaves: 8,
|
|
544
|
-
watchSpeakSec: 60,
|
|
545
|
-
tokenDailyBudget: 9000,
|
|
546
|
-
commentMaxChars: 120,
|
|
547
|
-
newAccountRamp: false,
|
|
548
|
-
},
|
|
549
|
-
};
|
|
550
|
-
},
|
|
551
|
-
};
|
|
552
|
-
|
|
553
|
-
panel.panels.stroll.mount(fake);
|
|
554
|
-
</script>
|
|
555
|
-
</body>
|
|
556
|
-
</html>
|
package/docs/panel-preview.png
DELETED
|
Binary file
|