`);分镜块=`段N(x-y秒)|场M:…`(一场可拆多段:场2前半/后半),`renderSbBlocks`→`.sb-block/.sb-head` - **改 data-pages.js renderModal**(仅 `visibleSb.length>0` 时绑定):`sync()`——①AI脚本列 `strong,h1-h4` 过滤 `/场\s*\d/` 得场标题数组(DOM 顺序=文档顺序)②`limit=aiBody.scrollTop+60`,找最后一个 `rect.top-aiTop+scrollTop <= limit` 的标题=当前场 ③正则提取场号 N ④分镜列 `.sb-block` 中 `find` 第一个 head 匹配 `场N(?=前半|后半|[::]|\s|$)` 的块 ⑤`sbBody.scrollTop = target.rect.top - sbBody.rect.top + sbBody.scrollTop`(不用 offsetTop,防 offsetParent 歧义);`aiBody.addEventListener('scroll', sync, {passive:true})` + 打开时 `sync()` 一次 - **⚠️ rAF 教训(重要)**:初版用 `requestAnimationFrame(sync)` 节流,CDP 9223 tab `visibilityState=hidden` **rAF 不触发**→联动失效;改为直接同步调用 sync(计算量小:30 strong + 8 块,性能无碍)。**CDP 验证场景禁依赖 rAF** - **⚠️ 测试脚本转义教训**:bash heredoc 写 `.mjs` 里 `/场\s*\d/` 单反斜杠 → Node 解析 JS 字符串时 `\s`→`s`(无效转义丢反斜杠)→ 正则变 `场s*\d` 不匹配,误判 2 小时;**JS 字符串里正则必须写 `\\s`**(Edit 工具直写文件的正则字面量不受影响,产品代码一直是对的) - **验证**(CDP reload 后):S0 打开弹窗初始对齐场1(sbScrollTop 12);滑到场3→分镜 4392 可见「场3:老屋堂屋·当天傍晚」;场5→8528「场5:老屋灶房·高三深夜」;回场1→12;四条链路全过 ## 场次联动回退单向 + 修复段名格式正则 bug(18:30-19:05) - **用户明确:不要双向联动,只允许 AI脚本为主导的联动**——删 `syncAi` 反向逻辑与 `sbBody.addEventListener('scroll', syncAi)`,仅保留 `syncSb`(AI脚本列滚动 → 分镜列对齐) - **🐛 P0 真 bug(本次核心)**:`syncSb` 里分镜块匹配正则 `场N(?=前半|后半|[::]|\s|$)` 只兼容「场N:标题」冒号格式与「前半/后半」段名;**video 190 实际 head 是「场1前段/场3中段/场3中后段/场4末段」**(前段/后段/中段/中后段/末段 5 种段名)→ 正则完全不匹配 → target 永远 undefined → **联动失效**(之前会话验证的「场3:老屋堂屋」是冒号格式数据,掩盖了此 bug) - **修复**:`new RegExp('场' + m[1] + '(?![0-9])')`——负向前瞻防 `场1` 误匹配 `场10`,兼容全部段名格式与冒号格式 - **验证**(CDP #/rewrites 页 video 190 rewrite 22,18 分镜块): - ① AI脚本主导:滚 400/800(limit 未跨场2标题 t=887)→ 仍对齐场1(正确);滚 1200(limit 1260 > 887)→ 分镜列 12→2473 对齐场2前段 ✅ - ② 分镜列独立:分镜列 600→3073,AI脚本列 1200 纹丝不动 ✅(无反向联动) - ③ 跳底:AI列 5621 → 分镜列 17480 对齐场6前段(场6 t=5567 ≤ limit 5681)✅ - **⚠️ CDP 新教训:`scrollTop` 赋值不触发 scroll 事件监听**(fired 0;Chrome 将 scroll 事件异步/合并派发),`dispatchEvent(new Event('scroll'))` 才触发(fired 1);**验证脚本必须设置 scrollTop 后手动补发 scroll 事件**;真实用户滚轮不受影响(真实滚动正常派发事件) - 测试脚本:保留 `cdp-verify-oneway2.mjs`(最终验证版),其余 cdp-probe/debug/regex/event 探针已删 ## 视频标题去首尾引号(18:34-18:45) - 用户反馈:video 190「他守住的不止是那份快递…」标题带引号,要去掉 - **根因**:`fmtTitleQ` 只清了尾部引号(`[\s"“”']+$`),开头引号没处理 → 弹窗显示 `《"他守住…》`;列表页完整标题(含 #标签)的引号在 `#` 前,也不在字符串首尾 - **修复**(app.js + data-pages.js): - app.js 新增 2 个工具:`stripTitleQuotes(s)`(清整串首尾引号:英文/中文双引号/单引号/「『」』,仅首尾中间保留)+ `cleanTitle(t)`(# 前主体去引号、# 标签原样保留——列表页完整标题用) - `fmtTitleQ` 改调 stripTitleQuotes(弹窗);列表页/视频详情/改写按钮 payload/首页最近脚本 8 处显示改调 cleanTitle - **验证**(CDP):列表页 `他守住的不止是那份快递,还守住了留守孩子们的那份期待#AI创作浪潮计划…` 无引号;弹窗 `《他守住的不止是那份快递…》⏎#…` 无引号 ✅ - 工具函数定义在 app.js 顶层(先加载),data-pages.js 直接复用(全局 lexical scope 共享) ## 查看改写弹窗宽度自适应(18:38-18:40) - 用户需求:「已改写 → N 查看」弹窗距网页左右各 50px,视口变宽弹窗跟着变宽,**最大 1400px** - **改 style.css 347 行**:`.rw-modal` width `min(1100px, 95vw)` → `min(1400px, calc(100% - 100px))`(全局 border-box,100% 相对 mask fixed inset:0 视口宽,不含滚动条) - **验证**(CDP 多视口):1200→1085(视口-100,左右 50/50);1400→1285;1600/1920/2200→1400 封顶居中 ✅ ## 移植 dsh「热门账号→导入」功能到工作台(19:15-19:35) - **用户需求**:「账号列表页就是dsh插件 热门账号,里面还有个导入功能看看能否移植过来」 - **dsh 原链路调研**(dsh-plugin-douyin-accounts/client.js + dsh-plugin-mcn/index.js):弹窗两种方式(方式一账号名/抖音号/地址 3 输入框、方式二本地文件夹路径)→ `POST /mcn/api/external/stage`(账号模式浏览器采集+AI会话确认,browserTaskRunning 409 互斥;目录模式直接 stage)→ preview(AI 确认前扫描比对不写库)→ import 写库 - **移植设计**(工作台不直连 dsh /mcn 接口):前端加「导入账号」按钮 + 同款弹窗 → 复用 `executeTask` 提交 prompt 任务到 `/api/run`(左侧 mcn-workshop 会话栏可见,与「保存并分析」同构)→ WorkBuddy AI 执行导入 → 轮询完成自动刷新;确认环节由弹窗「提交导入」承担(dsh 的 AI 会话确认 → 工作台的 executeTask 任务模式) - **改动**:app.js 新增 `download` 图标 + `openImportAccounts(btn)`(弹窗两种方式、空校验 toast「请填写抖音账号信息或文件夹路径」、prompt 按目录/账号两种拼法、label「导入指令」);data-pages.js renderAccounts 工具栏加「导入账号」按钮(svgIcon download);style.css 补 `.import-form` 4 类样式;帮助页「账号分析」组加问法「把抖音账号「俊希」导入账号列表」 - **验证**(CDP 9223 + fetch mock 零副作用):弹窗打开→4 输入框齐全→空提交 toast 校验→填账号提交→弹窗关闭+按钮「执行中…」+ /api/run prompt 正确→mock done 轮询→按钮恢复「导入」✅;帮助页问法 13 条含导入 ✅ - **⚠️ 两个坑**:①页面有常驻隐藏 `#settingsModal`(index.html 静态弹窗),DOM 选择器查弹窗必须 `.modal-mask:not([hidden])`(否则匹配到设置弹窗误判);②fetch mock 判断顺序必须 `/api/run/status` 在前(`includes('/api/run')` 会先吞掉 status 请求) - 验证脚本保留 `cdp-verify-import.mjs`(含 fetch mock 模式,可复用) ## 查看弹窗:展开源脚本按钮移入 AI脚本 标题 + 弹窗最大宽度 1600(18:48-19:00) - 用户需求:①「展开原脚本」按钮图标放到 **AI脚本 标题右边,间隔 10px**(原在弹窗顶部 modal-title-row)②弹窗最大宽度 1400→**1600** - **改 data-pages.js**:modal-title-row 删 data-src-toggle(保留标题+×);AI脚本列 `.rw-sec-head` 内追加 `