移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。
**目前能用的(真环境实测,非推断)**:
profile/other : 200, 7075 字节 —— 博主主页指标(粉丝/获赞/作品数/昵称)
aweme/detail : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)
**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
挑中的恰好是「批量拉作品列表」这个最敏感的动作。
2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
代价,过几小时要重测)。
所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。
**排查中控住变量后得到的两条事实**(都写进注释了):
· `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
(我先前猜的 sec-ch-ua 不是关键。)
· 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
从 CDP 取齐 cookie + UA + hints,而不是各自写死。
「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。
测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
13 KiB
导演工作室 · 重新设计方案
2026-10-10 · 基于实测盘查(非推测) 目标:止住"越改越乱",把现有能力重新收进一个边界清晰的结构里
一、现状诊断(全部实测数据)
1.1 规模
| 项 | 数量 | 说明 |
|---|---|---|
| 前端视图 | 85 个 | 视频工厂相关 44 个 |
| 后端路由 | 7 文件 / 145 端点 / 7206 行 | ave(33) · ave_project(30) · ave_keyframe(25) · ave_assets(33) · ave_scene(5) · ave_creatives(16) · ave_docs(3) |
ave-director.js |
112 KB | 单文件注册 26 个 window._dir* 函数 |
| 项目对象顶层键 | 19 个 | 其中 3 个是从没写过的死键 |
| 运行目录 | 15 个 | 含 5 个测试残留 |
1.2 五类具体问题(都对齐到了文件)
① 空壳页面 4 个(内容是"功能开发中,敬请期待")
ave-script.js 409 B 脚本生成
ave-render.js 409 B 渲染任务
ave-templates.js 406 B 模板
ave-materials.js 409 B 素材库
② 新旧两套流程并存 —— 6 个老流程页在菜单里,但跑不通
ave-flow-short-drama.js 744 B ← 菜单「🎭 短剧创作」
ave-flow-dub.js 647 B ← 菜单「🎙️ 基础口播」
ave-flow-beat.js 579 B ← 菜单「🥁 卡点视频」
ave-flow-narrative.js 668 B ← 菜单「📖 角色叙事」
ave-flow-digital-human.js 611 B ← 菜单「👤 数字人口播」
ave-flow-hybrid.js 564 B ← 菜单「🎞️ 口播+混剪」
它们自己的注释写着:"TTS / 素材 / BGM / 字幕的执行实现仍在接入中(运行时会明确跳过)" → 而工作室那条链路是通的 → 两套并存,用户不知道点哪个
③ 工作室内部职责重叠(用户已经混了)
🌍 设定 vs 📋 创意卡 —— 都在"想清楚这个故事"
🖼 关键帧设计 vs 🖼 关键帧 —— 用户明确问过"这两个有什么区别"
实测:用户上次说的"关键帧工作台里面是空的",我查了两轮才确认他指的是哪个页面。
④ 单文件职责超载
ave-director.js(112 KB)一个文件里塞了:
<!-- ② 全局设置 --> 导演系统 / 风格 / 演员表 / 场景 / seed
<!-- 📐 全片设定 --> 空间/角色/镜头语言(原故事板并入)
<!-- ③ 按场次生成 --> 段落列表 + 场记板 + 生成
<!-- ④ 分镜表 --> 镜头卡片编辑
<!-- 出片进度 --> 渲染任务轮询
⑤ 数据源分散 + 死键
projects/{pid}/project.json ← 项目对象(19 键,其中 3 键为空)
storyboards/{pid}.json ← 分镜(不在 project.json)
keyframes/{pid}/{sid}/ ← 关键帧图
keyframe_videos/{pid}/{sid}/ ← 视频片段
project.json 里的 keyframes / videos / assets 三个键从没被写过(空)。
实测 _enrich() 每次读项目时临时合并前三个 → 说明它们本该在项目对象里。
二、根因(为什么会"越改越乱")
三条,都不是技术问题:
- 加功能时"就地扩" —— 没有"这一层该管什么"的边界。分镜页越塞越多(演员表、锚点、全片设定、出片设置),因为"顺手就放这了"。
- 新旧并存不删 —— 怕删坏,就留着旧的。结果路由/菜单/文档里同时存在两套,用户选错就在所难免。
- 数据"能跑就行" —— 写在哪方便就写哪。分镜写
storyboards/、关键帧写keyframes/,导致"上游带入"读不到(这是之前修过的真 bug)。
三、新架构
3.1 三条主线(先分清楚"这是哪一类东西")
📦 原料 🎬 生产 📊 交付
(可复用资产) (做一条片子) (看结果)
角色/场景/道具 导演工作室 生产记录
音色/BGM/音效 (唯一主流程) 费用统计
产品/服装/素材 产物中心
判断规则:
- 能被多条片子复用 → 进「原料」
- 属于某一条片子的 → 进「生产」
- 是结果/统计 → 进「交付」
3.2 生产主线:工作室 9 阶段 → 7 阶段
合并的关键点:🖼 关键帧设计 + 🖼 关键帧 → 一个页面(左设计右图)
① 💡 创意 ┐
② 🌍 设定 ├→ ③ 📋 创意卡 → ④ 📝 剧本 → ⑤ 🎬 分镜 → ⑥ 🖼 关键帧 → ⑦ 🎞 视频 → ⑧ 🎙 后期
┘
(素材层) (汇聚层) (执行层)
为什么保留 ①②(不合并):
💡 创意= 这个故事的种子(候选 → 选一句)🌍 设定= 世界的规则(可跨故事复用,比如"肛肠科病房"这个世界的规则)📋 创意卡= 两者合起来 → 这个故事的具体构想- 职责不同,但界面上必须写明各自管什么(现在的毛病是没写)
为什么合并 ⑥:
- 用户已经混了。而且"设计"(决定拆几张)和"生成"(出图)本来就是同一步的两半 —— 设计完立刻要看图对不对。
3.3 每阶段一张「职责卡」(界面顶部固定显示)
这是治乱的核心:每个页面顶部明确写三行 —— 我从哪来 / 我产出什么 / 下一步用它做什么。
| # | 阶段 | 输入(从哪来) | 产出 | 下一步用它做什么 |
|---|---|---|---|---|
| ① | 💡 创意 | 参数选型 | 选中的 1 句话 | 扩写成创意卡 |
| ② | 🌍 设定 | — | 世界规则(可复用) | 创意卡 + 剧本的世界观依据 |
| ③ | 📋 创意卡 | 创意 + 设定 | 故事卡(12 字段) | 剧本的最高依据 |
| ④ | 📝 剧本 | 创意卡 | 按段落的剧本 | 分镜按段落做 |
| ⑤ | 🎬 分镜 | 剧本段落 + 导演/风格/演员 | 镜头(Shot) | 关键帧按镜头做 |
| ⑥ | 🖼 关键帧 | 镜头 + 角色/场景资产 | 帧设计(A/B/C)+ 帧图 | 视频的首/尾帧 |
| ⑦ | 🎞 视频 | 关键帧(选首尾)+ 引擎 | 视频片段(可多段) | 后期拼接 |
| ⑧ | 🎙 后期 | 采用的片段 | 成片(拼接/字幕/混音) | 交付 |
3.4 菜单重排
现状 → 目标
🎬 视频工厂 · 资源库(16 项) → 📦 原料(12 项)
摘掉:素材库(空壳)
保留:创意库 / 角色库 / 角色生成器 / 场景生成器 / 场景库 /
真实场地 / 道具库 / 产品库 / 服装库 / 音色库 / BGM / 音效
说明:环境音库、特效预设 暂藏在「更多」里(当前为空,用不上)
🎬 视频工厂 · 流程(12 项) → 🎬 生产(3 项)
★ 导演工作室(唯一主流程)
🔄 人物置换(独立工具,不属主流程)
🔀 流程画布(高级功能,折叠在「高级」下)
隐藏:6 个 ave-flow-*(老流程,跑不通)+ 新建流程(与流程画布重复)
🎬 视频工厂 · 能力中心(4 项) → 🧩 配置(4 项,不变)
🎬 视频工厂 · 运营(2+ 项) → 📊 交付(3 项)
生产记录 / 费用统计 / 产物中心
净减:16+12+4+2 = 34 项 → 12+3+4+3 = 22 项(-35%)
3.5 拆掉 112 KB 的巨物
ave-director.js 拆成 3 个视图(各管一件事):
views/studio-shots-config.js ← 导演系统 / 风格 / 演员表 / 场景 / 锚点(配置)
views/studio-shots-generate.js ← 段落列表(场记板)/ 生成 / 全片设定(动作)
views/studio-shots-table.js ← 分镜表(结果,可编辑)
用户在一个页面里从上到下走,但代码是三块,各自可独立改。
四、数据模型(单一真相源)
4.1 原则
一条片子的全部数据,只在一个文件里。 媒体文件(图/视频/音频)仍各自落盘,但路径登记在项目对象里。
4.2 目标结构
⚠️ 权衡说明(我先自我修正):
我最初想把 shots(含关键帧和视频的全部版本记录)塞进 project.json。
但那样会让它膨胀到几百 KB —— 20 个镜头 × 每镜 3 帧 × 每帧多版本,
每次改一个字都要重写整个文件,性能和并发都会出问题。
所以改成:单一真相源 = 单一目录,而不是单一文件。
projects/{pid}/ ← ★ 一个项目 = 一个目录(这就是"真相源")
│
├ project.json ← 轻量(< 20 KB):元数据 + 各阶段摘要
│ { "project_id","title","stage","created_at","updated_at",
│ "creative":{...}, // 💡 创意(选中的候选)
│ "setting":{...}, // 🌍 设定
│ "creative_card":{...}, // 📋 创意卡
│ "script":{...}, // 📝 剧本(段落)
│ "film_settings":{...}, // 📐 全片设定
│ "post":{...}, // 🎙 后期(时间线 + 成片路径)
│ "cast":[...], // 演员表
│ "history":[...] } // 变更记录
│
├ shots.json ← 重数据:分镜 + 关键帧 + 视频(可单独读写)
│ [ { "shot_id","paragraph_no","visual","duration","cast_slots", ...,
│ "keyframes": { "plan":{A/B/C 提示词},
│ "frames":[{seq,role,versions:[{v,file,adopted}]}] },
│ "videos": [ {segment, versions:[{v,file,adopted,has_voice}]} ] } ]
│
└ media/ ← 媒体文件(或继续用现目录,只登记路径)
keyframes/shot_01/v1.png
videos/shot_01/s1_v1.mp4
为什么这样更好:
project.json保持轻量 → 改设定/剧本不会牵动分镜shots.json单独读写 → 生成一镜只改这个文件- 但对外只有"一个项目目录" → 备份/复制/迁移 = 复制目录
取消:
project.json里的keyframes/videos/assets三个死键 → 删除storyboards/{pid}.json作为独立位置 → 并入projects/{pid}/shots.json(同级目录,不再是"另一个地方")- 前端不再需要
_enrich()跨目录临时合并
4.3 收益
- 「上游带入」天然正确(同一目录,不用跨目录捞)
- 「这个项目的全部产物」一个请求拿到
- 备份/迁移/复制项目 = 复制一个目录
- 删项目 = 删一个目录(现在要删 4 个地方)
五、迁移路径(现有内容怎么落位)
原则:不删数据,只搬家。每一步都可回滚(先备份)。
| 现有 | 去向 |
|---|---|
storyboards/{pid}.json 的 shots |
搬进 project.json 的 shots[] |
keyframes/{pid}/{sid}/*.png |
文件不动;路径登记到 shots[i].keyframes |
keyframe_videos/{pid}/{sid}/*.mp4 |
文件不动;路径登记到 shots[i].videos |
storyboard_paper |
已是 film_settings 的来源(已迁移)→ 删键 |
6 个 ave-flow-* 视图 |
文件保留(不删仓库文件),仅从菜单摘掉 |
| 4 个空壳视图 | 同上,从菜单摘掉(它们本来也不在菜单里) |
| 运行目录里的测试残留 | 移到 _trash/ |
六、实施顺序(4 批,每批独立可验证)
批 1 · 止血(零风险,先让界面不乱)
- 菜单重排(摘掉老流程 + 空壳)
- 每个阶段页顶部加「职责卡」(我产出什么 / 下一步用它做什么)
- 合并
🖼 关键帧设计+🖼 关键帧为一个页面
批 2 · 数据归一(动后端,但只加不改)
shots搬进project.json(写入时双写,读取时优先新位置)- 关键帧/视频的路径登记进
shots[i] - 前端改读新位置(保留旧路径兜底)
批 3 · 拆巨物
ave-director.js拆 3 块(配置 / 生成 / 表)- 每块独立测试
批 4 · 清理
- 删死键、废弃
_enrich()、测试残留移_trash/ - 更新文档
七、待你确认的 5 件事
- 要不要合并「关键帧设计」和「关键帧」?(我倾向合并 —— 你已经混过一次)
ave-flow-*那 6 个老流程页,从菜单摘掉可以吗?(文件保留)- 「环境音库」当前是空的 —— 先藏起来,还是保留在菜单里?
- 「流程画布」(
workflow) 你还用吗?(它是另一套编排方式,功能与工作室重叠) - 批 1 的菜单重排,要不要现在就做?(零风险,改完立刻清爽)
附:本次盘查用到的命令(可复现)
# 视图规模
ls -la frontend/src/views/*.js | awk '{print $5, $NF}' | sort -rn
# 空壳识别
for f in views/*.js; do [ $(wc -c < $f) -lt 1000 ] && echo "$f"; done
# 后端端点分布
for f in routes/ave*.py; do echo "$(basename $f) $(grep -cE '^@router\.' $f)"; done
# 项目对象结构
python3 -c "import json;d=json.load(open('.../project.json'));print(list(d.keys()))"