@remixmate/cli 0.1.0 → 0.1.1
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/README.md +100 -83
- package/README.zh-CN.md +183 -0
- package/dist/handlers/gen-digital-human.d.ts +12 -0
- package/dist/handlers/gen-digital-human.js +157 -0
- package/dist/handlers/gen-image.js +5 -41
- package/dist/handlers/gen-video.d.ts +18 -0
- package/dist/handlers/gen-video.js +153 -0
- package/dist/handlers/gen-voice.js +2 -12
- package/dist/handlers/index.js +4 -2
- package/dist/handlers/shared.d.ts +26 -0
- package/dist/handlers/shared.js +66 -0
- package/dist/http.d.ts +4 -2
- package/dist/http.js +5 -3
- package/dist/manifest.json +27 -24
- package/dist/registry.d.ts +5 -16
- package/dist/registry.js +11 -17
- package/dist/skill-schema.d.ts +47 -0
- package/dist/skill-schema.js +49 -0
- package/package.json +5 -4
- package/skills/export-jianying/scripts/gen_jianying_draft.py +4 -4
- package/skills/gen-digital-human/SKILL.md +23 -46
- package/skills/gen-digital-human/skill.json +3 -2
- package/skills/gen-digital-human/version.json +1 -1
- package/skills/gen-image/SKILL.md +2 -2
- package/skills/gen-image/skill.json +2 -1
- package/skills/gen-image/version.json +1 -1
- package/skills/gen-script/SKILL.md +13 -13
- package/skills/gen-script/scripts/gen_script.py +11 -12
- package/skills/gen-video/SKILL.md +22 -33
- package/skills/gen-video/skill.json +3 -2
- package/skills/gen-video/version.json +1 -1
- package/skills/gen-voice/SKILL.md +1 -1
- package/skills/gen-voice/version.json +1 -1
- package/skills/prepare-video-assets/SKILL.md +2 -2
- package/skills/prepare-video-assets/skill.json +1 -1
- package/skills/render-video/scripts/render_video.py +8 -8
- package/skills/{template-bind → template-registry}/README.md +4 -4
- package/skills/{template-bind → template-registry}/SKILL.md +14 -12
- package/skills/template-registry/scripts/list_templates.py +129 -0
- package/skills/{template-bind → template-registry}/scripts/match_template.py +4 -3
- package/skills/{template-bind → template-registry}/scripts/registry_loader.py +1 -1
- package/skills/{template-bind → template-registry}/scripts/template_paths.py +7 -7
- package/skills/{template-bind → template-registry}/skill.json +6 -5
- package/skills/template-registry/version.json +7 -0
- package/skills/{template-bind → template-registry}/video_dsl/README.md +2 -2
- package/skills/{template-bind → template-registry}/video_dsl/runtime/__init__.py +1 -1
- package/skills/video-parser/SKILL.md +47 -160
- package/skills/video-parser/skill.json +3 -4
- package/skills/video-parser/version.json +1 -1
- package/skills/web-capture/SKILL.md +407 -116
- package/skills/web-capture/scripts/_media_screenshot/__init__.py +21 -0
- package/skills/web-capture/scripts/_media_screenshot/bootstrap.py +34 -0
- package/skills/web-capture/scripts/_media_screenshot/browser.py +86 -0
- package/skills/web-capture/scripts/_media_screenshot/cli_args.py +111 -0
- package/skills/web-capture/scripts/_media_screenshot/js/arrow.js +86 -0
- package/skills/web-capture/scripts/_media_screenshot/js/caption.js +27 -0
- package/skills/web-capture/scripts/_media_screenshot/js/clear_overlay.js +5 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_bootstrap.js +26 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_hide.js +6 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_move.js +12 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_ripple.js +25 -0
- package/skills/web-capture/scripts/_media_screenshot/js/element_zoom.js +72 -0
- package/skills/web-capture/scripts/_media_screenshot/js/element_zoom_restore.js +21 -0
- package/skills/web-capture/scripts/_media_screenshot/js/fade_out_overlays.js +10 -0
- package/skills/web-capture/scripts/_media_screenshot/js/focus.js +38 -0
- package/skills/web-capture/scripts/_media_screenshot/js/highlight.js +97 -0
- package/skills/web-capture/scripts/_media_screenshot/js/overlay_bootstrap.js +19 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_in.js +54 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_out.js +11 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_restore.js +13 -0
- package/skills/web-capture/scripts/_media_screenshot/js/redact.js +33 -0
- package/skills/web-capture/scripts/_media_screenshot/js/scroll.js +26 -0
- package/skills/web-capture/scripts/_media_screenshot/js/scroll_through.js +18 -0
- package/skills/web-capture/scripts/_media_screenshot/js/sequence.js +76 -0
- package/skills/web-capture/scripts/_media_screenshot/js/settled_check.js +15 -0
- package/skills/web-capture/scripts/_media_screenshot/js/title_card.js +71 -0
- package/skills/web-capture/scripts/_media_screenshot/js_loader.py +14 -0
- package/skills/web-capture/scripts/_media_screenshot/overlay.py +17 -0
- package/skills/web-capture/scripts/_media_screenshot/recording.py +100 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/__init__.py +39 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/arrow.py +50 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/caption.py +20 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/click.py +35 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/code_lines.py +54 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/focus.py +24 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/highlight.py +54 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/hover.py +28 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/redact.py +32 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/scroll.py +32 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/sequence.py +43 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/title_card.py +20 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/type.py +42 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/wait.py +9 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/zoom.py +72 -0
- package/skills/web-capture/scripts/_media_screenshot/screenshot.py +166 -0
- package/skills/web-capture/scripts/_media_screenshot/storyboard.py +88 -0
- package/skills/web-capture/scripts/_media_screenshot/template.py +119 -0
- package/skills/web-capture/scripts/_media_screenshot/trim.py +82 -0
- package/skills/web-capture/scripts/record.py +186 -0
- package/skills/web-capture/scripts/screenshot.py +94 -0
- package/skills/web-capture/skill.json +14 -14
- package/skills/web-capture/templates/github-code-tour.json +59 -0
- package/skills/web-capture/templates/github-readme-tour.json +77 -0
- package/skills/web-capture/templates/github-repo-intro.json +74 -0
- package/skills/web-capture/version.json +2 -2
- package/dist/handlers/template-bind.d.ts +0 -15
- package/dist/handlers/template-bind.js +0 -149
- package/skills/gen-digital-human/scripts/gen_digital_human_video.py +0 -574
- package/skills/gen-video/scripts/gen_video.py +0 -591
- package/skills/template-bind/version.json +0 -7
- package/skills/web-capture/scripts/web_capture.py +0 -461
- /package/skills/{template-bind → template-registry}/scripts/check_contracts.py +0 -0
- /package/skills/{template-bind → template-registry}/scripts/render_job_client.py +0 -0
- /package/skills/{template-bind → template-registry}/scripts/sync_registry.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/dsl_validator.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/prompt_enhancer.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/template_binder.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/timeline_compiler.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/render-plan-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/template-binding-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/template-definition-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/video-dsl-v1alpha1.json +0 -0
|
@@ -1,183 +1,474 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: web-capture
|
|
3
3
|
description: |
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
网页截屏 / 录屏 / 分镜视频技能,基于 Playwright Python,对任意 URL 落盘到本地。
|
|
5
|
+
支持:整页 / 元素 / 区域截屏、固定时长 / 条件触发录屏、自动滚动录屏、分镜视频(高亮 / 聚焦 / 放大 / 滚动 / 虚拟光标点击 / 字幕 / 标题卡 / 箭头 / 编号序列 / 打码 / 代码行高亮)。
|
|
6
|
+
|
|
7
|
+
当用户提到以下任何需求时,立即使用本 skill:
|
|
8
|
+
- 网页截图、网页截屏、整页截图、长截图、full page screenshot
|
|
9
|
+
- 截某个元素 / 区域、局部截屏、focus 某个区域
|
|
10
|
+
- 录屏、网页录制、录制视频、录一段操作、生成 webm
|
|
11
|
+
- 滚动录屏、页面从头划到尾的视频
|
|
12
|
+
- 多场景视频、分镜视频、storyboard、按时间线编排(红框高亮 / 局部放大 / 滚动介绍)
|
|
13
|
+
- 演示点击 / 输入 / 悬停(虚拟鼠标 + 涟漪 / 打字机 / 触发 tooltip)
|
|
14
|
+
- 加箭头、加字幕条、加标题卡 / 片头片尾、按顺序编号高亮多个区域
|
|
15
|
+
- 截图前隐藏元素 / 涂盖打码(cookie banner、敏感信息)
|
|
16
|
+
- 给静态截图加注释(红框 / 箭头 / 标签)
|
|
17
|
+
- 高亮某文件的 L5-L20 代码行
|
|
18
|
+
- 等待元素出现/消失后再截屏或停止录屏
|
|
19
|
+
- 移动端 / 设备模拟(iPhone / Pixel 等)
|
|
20
|
+
- 带 cookie / 登录态、storageState 截屏 / 录屏
|
|
21
|
+
|
|
22
|
+
即使用户没明确提「playwright」,只要他们想对一个 URL 截屏/录屏/做分镜视频并拿到本地文件,也要使用本 skill。
|
|
12
23
|
triggers:
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
24
|
+
- 网页截图、网页截屏、整页截图、长截图、full page screenshot
|
|
25
|
+
- 截某个元素 / 区域、局部截屏、focus 某个区域
|
|
26
|
+
- 录屏、网页录制、录制视频、录一段操作、生成 webm
|
|
27
|
+
- 滚动录屏、页面从头划到尾的视频
|
|
28
|
+
- 多场景视频、分镜视频、storyboard、按时间线编排
|
|
29
|
+
- 演示点击 / 输入 / 悬停(虚拟鼠标 + 涟漪 / 打字机 / 触发 tooltip)
|
|
30
|
+
- 加箭头、加字幕条、加标题卡 / 片头片尾、按顺序编号高亮多个区域
|
|
31
|
+
- 截图前隐藏元素 / 涂盖打码、给静态截图加注释(红框 / 箭头 / 标签)
|
|
32
|
+
- 移动端 / 设备模拟、带 cookie / 登录态截屏 / 录屏
|
|
16
33
|
---
|
|
17
34
|
|
|
18
|
-
#
|
|
35
|
+
# 网页截屏 / 录屏 Skill
|
|
19
36
|
|
|
20
|
-
|
|
37
|
+
两个入口脚本,纯 Python 实现:
|
|
21
38
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
- **Record video** — Playwright's native context recording (webm), transcoded to MP4.
|
|
39
|
+
- **`scripts/screenshot.py`** — 截图。整页 / 视口 / 元素 / 区域。
|
|
40
|
+
- **`scripts/record.py`** — 录屏(webm)。固定时长 / 条件停止 / 自动滚动 / 分镜(storyboard)/ **模板(templates/)**。
|
|
25
41
|
|
|
26
|
-
|
|
42
|
+
底层共享 **`scripts/_media_screenshot/`** 包,封装 Playwright Python API + 所有浏览器侧 JS 注入(overlay / zoom / scroll 等)。
|
|
27
43
|
|
|
28
|
-
|
|
44
|
+
**模板目录** `templates/`:参数化的 storyboard,常见场景一行命令出片。详见下文 "分镜视频 / 模板"。
|
|
29
45
|
|
|
30
|
-
|
|
46
|
+
> 路径约定:读取系统注入的 `Base directory for this skill: <path>` 作为 `<SkillDir>`,命令里的 `<SkillDir>` 替换为该路径,切勿硬编码绝对路径。`python` 在 macOS 上可能需写成 `python3`。
|
|
31
47
|
|
|
32
|
-
|
|
33
|
-
- **ffmpeg**: must be installed locally (`brew install ffmpeg`) — used to assemble the scroll-video frames and transcode native recordings to MP4. Same dependency the `video-parser` skill relies on.
|
|
48
|
+
## 前置依赖
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
- **Python 3.9+**
|
|
51
|
+
- **`playwright` pip 包 + chromium 内核**:首次运行**自动 bootstrap**——脚本检测到缺包会执行 `pip install playwright` + `playwright install chromium`。
|
|
52
|
+
- 也可提前手动装:
|
|
53
|
+
```bash
|
|
54
|
+
pip install playwright
|
|
55
|
+
playwright install chromium
|
|
56
|
+
```
|
|
57
|
+
- **ffmpeg**(可选):仅 storyboard 模式用来精确裁剪开头加载段。无 ffmpeg 时会保留原片并提示。
|
|
36
58
|
|
|
37
|
-
##
|
|
59
|
+
## 截屏 `screenshot.py`
|
|
38
60
|
|
|
39
|
-
|
|
61
|
+
### 最小用法
|
|
40
62
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
```bash
|
|
64
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
65
|
+
--url "https://example.com" \
|
|
66
|
+
--output "example.png"
|
|
67
|
+
```
|
|
45
68
|
|
|
46
|
-
|
|
69
|
+
### 整页截图
|
|
47
70
|
|
|
48
|
-
|
|
71
|
+
```bash
|
|
72
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
73
|
+
--url "https://example.com" \
|
|
74
|
+
--output "example_full.png" \
|
|
75
|
+
--full-page
|
|
76
|
+
```
|
|
49
77
|
|
|
50
|
-
|
|
51
|
-
|---------|-------------|---------|
|
|
52
|
-
| `WEB_CAPTURE_BROWSER` | Default browser engine (`--browser` overrides). | `chromium` |
|
|
53
|
-
| `WEB_CAPTURE_OUTPUT_BASE` | Base dir for the auto-created temp output dir. | system tempdir |
|
|
54
|
-
| `WEB_CAPTURE_NO_SANDBOX` | Set `1` to add `--no-sandbox` (only for containers that can't use user namespaces). | unset (sandbox on) |
|
|
55
|
-
| `WEB_CAPTURE_ALLOW_PRIVATE_HOSTS` | Set `1` to disable the private/internal-IP SSRF block (single-tenant / trusted intranet only). | unset (block on) |
|
|
56
|
-
| `PLAYWRIGHT_BROWSERS_PATH` | Playwright browser binary location (provided by the runtime). | Playwright default |
|
|
78
|
+
### 元素截屏(局部 focus)
|
|
57
79
|
|
|
58
|
-
|
|
80
|
+
按 CSS 选择器截**元素本身**(自动 `scrollIntoViewIfNeeded`):
|
|
59
81
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
```bash
|
|
83
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
84
|
+
--url "https://example.com" \
|
|
85
|
+
--output "card.png" \
|
|
86
|
+
--selector ".card.featured" \
|
|
87
|
+
--wait-for-selector ".card.featured"
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
如不希望自动滚动:加 `--no-scroll-into-view`。
|
|
64
91
|
|
|
65
|
-
###
|
|
92
|
+
### 区域截屏(像素矩形 clip)
|
|
66
93
|
|
|
67
94
|
```bash
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
--
|
|
95
|
+
# 全页像素坐标
|
|
96
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
97
|
+
--url "https://example.com" \
|
|
98
|
+
--output "region.png" \
|
|
99
|
+
--clip "100,200,600,400" # x, y, w, h
|
|
100
|
+
|
|
101
|
+
# 以元素为基点偏移裁剪(先 scrollIntoView 该元素,再用其 boundingBox 起点 + 偏移裁剪)
|
|
102
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
103
|
+
--url "https://example.com" \
|
|
104
|
+
--output "region_in_card.png" \
|
|
105
|
+
--selector ".card" \
|
|
106
|
+
--clip "0,0,300,180"
|
|
71
107
|
```
|
|
72
108
|
|
|
73
|
-
###
|
|
109
|
+
### 移动端 / 设备模拟
|
|
74
110
|
|
|
75
111
|
```bash
|
|
76
|
-
python3 <SkillDir>/scripts/
|
|
77
|
-
--url "https://example.com" \
|
|
78
|
-
--
|
|
112
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
113
|
+
--url "https://m.example.com" \
|
|
114
|
+
--output "mobile.png" \
|
|
115
|
+
--device "iPhone 15 Pro" \
|
|
79
116
|
--full-page
|
|
80
117
|
```
|
|
81
118
|
|
|
82
|
-
|
|
119
|
+
自定义 viewport:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
123
|
+
--url "https://example.com" \
|
|
124
|
+
--output "wide.png" \
|
|
125
|
+
--viewport "1440,900"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 等待动态内容
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# 等待选择器出现
|
|
132
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
133
|
+
--url "https://example.com" \
|
|
134
|
+
--output "ready.png" \
|
|
135
|
+
--wait-for-selector "main .loaded" \
|
|
136
|
+
--timeout 30000
|
|
137
|
+
|
|
138
|
+
# 固定延时(适合纯前端动画)
|
|
139
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
140
|
+
--url "https://example.com" \
|
|
141
|
+
--output "delayed.png" \
|
|
142
|
+
--wait-for-timeout 2000
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### 隐藏 / 涂盖元素
|
|
83
146
|
|
|
84
147
|
```bash
|
|
85
|
-
|
|
148
|
+
# 隐藏 cookie banner、登录浮层等干扰元素(可重复)
|
|
149
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
86
150
|
--url "https://example.com" \
|
|
87
|
-
--
|
|
88
|
-
--selector "
|
|
151
|
+
--output "clean.png" \
|
|
152
|
+
--hide-selector ".cookie-banner" \
|
|
153
|
+
--hide-selector "#login-modal"
|
|
154
|
+
|
|
155
|
+
# 涂盖敏感信息(Playwright 原生 mask,默认粉色,可自定义颜色)
|
|
156
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
157
|
+
--url "https://app.example.com/dashboard" \
|
|
158
|
+
--output "redacted.png" \
|
|
159
|
+
--mask-selector ".user-email" \
|
|
160
|
+
--mask-selector ".api-token" \
|
|
161
|
+
--mask-color "#222"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### 静态截图加注释(红框 / 箭头 / 字幕 / 编号 / 打码)
|
|
165
|
+
|
|
166
|
+
`--annotate` 接受一份 JSON(路径或字符串),里面用 storyboard 的场景类型描述要画的注解。所有场景在截屏前一次性画好。
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
170
|
+
--url "https://github.com/user/repo" \
|
|
171
|
+
--output "annotated.png" \
|
|
172
|
+
--annotate annotate.json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`annotate.json` 示例:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
{
|
|
179
|
+
"annotations": [
|
|
180
|
+
{ "type": "highlight", "selector": "strong[itemprop=\"name\"] a",
|
|
181
|
+
"color": "#ff3b30", "label": "看这里" },
|
|
182
|
+
{ "type": "arrow",
|
|
183
|
+
"from": { "selector": "#repo-stars-counter-star" },
|
|
184
|
+
"to": { "selector": "strong[itemprop=\"name\"] a", "side": "right" },
|
|
185
|
+
"color": "#ff9500", "label": "⭐" },
|
|
186
|
+
{ "type": "caption", "text": "项目主页", "position": "bottom" },
|
|
187
|
+
{ "type": "redact", "selectors": [".user-email"], "mode": "blur" }
|
|
188
|
+
],
|
|
189
|
+
"settleMs": 900
|
|
190
|
+
}
|
|
89
191
|
```
|
|
90
192
|
|
|
91
|
-
|
|
193
|
+
> 顶层也可以直接是数组:`[{"type": "highlight", ...}]`。`settleMs` 是画完后等动画稳定再截屏的时长,默认 900ms。
|
|
194
|
+
|
|
195
|
+
### 带登录态截屏
|
|
196
|
+
|
|
197
|
+
两种方式,二选一:
|
|
198
|
+
|
|
199
|
+
**A. 直接传 storageState(推荐)**
|
|
92
200
|
|
|
93
201
|
```bash
|
|
94
|
-
python3 <SkillDir>/scripts/
|
|
95
|
-
--url "https://
|
|
96
|
-
--
|
|
97
|
-
--
|
|
98
|
-
--fps 30 \
|
|
99
|
-
--scroll-duration 8
|
|
202
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
203
|
+
--url "https://app.example.com/dashboard" \
|
|
204
|
+
--output "dashboard.png" \
|
|
205
|
+
--storage-state "./auth.json"
|
|
100
206
|
```
|
|
101
207
|
|
|
102
|
-
|
|
208
|
+
> `auth.json` 可由 `npx playwright codegen --save-storage=auth.json <url>` 在登录后导出。
|
|
103
209
|
|
|
104
|
-
|
|
210
|
+
**B. 仅传 cookies JSON**
|
|
105
211
|
|
|
106
212
|
```bash
|
|
107
|
-
python3 <SkillDir>/scripts/
|
|
213
|
+
python3 <SkillDir>/scripts/screenshot.py \
|
|
214
|
+
--url "https://app.example.com/dashboard" \
|
|
215
|
+
--output "dashboard.png" \
|
|
216
|
+
--cookies "./cookies.json"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
cookies 顶层必须是数组,每项遵循 Playwright cookie 格式:
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
[
|
|
223
|
+
{"name": "session", "value": "abc", "domain": ".example.com", "path": "/", "httpOnly": true, "secure": true}
|
|
224
|
+
]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### screenshot.py 参数
|
|
228
|
+
|
|
229
|
+
| 参数 | 说明 | 默认 |
|
|
230
|
+
|------|------|------|
|
|
231
|
+
| `-u` / `--url` | 目标 URL(必填) | — |
|
|
232
|
+
| `-o` / `--output` | 本地输出路径 | `screenshot.png` |
|
|
233
|
+
| `-b` / `--browser` | `chromium` / `firefox` / `webkit` | `chromium` |
|
|
234
|
+
| `--device` | 设备模拟名 | 无 |
|
|
235
|
+
| `--viewport` | `"宽,高"` | 无 |
|
|
236
|
+
| `--full-page` | 整页截屏 | 关 |
|
|
237
|
+
| `--selector` | 截元素本身 | 无 |
|
|
238
|
+
| `--clip` | `"x,y,w,h"` 区域截屏;和 selector 同设时基于元素 boundingBox 偏移 | 无 |
|
|
239
|
+
| `--no-scroll-into-view` | selector 模式下关闭自动滚动 | 关 |
|
|
240
|
+
| `--wait-for-selector` | 操作前等待选择器出现 | 无 |
|
|
241
|
+
| `--wait-for-timeout` | 操作前固定等待(ms) | 无 |
|
|
242
|
+
| `--color-scheme` | `light` / `dark` / `no-preference` | 无 |
|
|
243
|
+
| `--user-agent` | 覆盖 UA | 无 |
|
|
244
|
+
| `--timeout` | Playwright 全局超时(ms) | 无 |
|
|
245
|
+
| `--ignore-https-errors` | 忽略证书错误 | 关 |
|
|
246
|
+
| `--storage-state` | storageState JSON 文件路径 | 无 |
|
|
247
|
+
| `--cookies` | cookies JSON 字符串或文件 | 无 |
|
|
248
|
+
| `--hide-selector` | 截屏前 display:none 该选择器,可重复 | 无 |
|
|
249
|
+
| `--mask-selector` | Playwright 原生 mask 涂盖该选择器,可重复 | 无 |
|
|
250
|
+
| `--mask-color` | mask 填充色 | Playwright 粉 |
|
|
251
|
+
| `--annotate` | 注释 JSON 文件或字符串(数组或 `{annotations, settleMs}`) | 无 |
|
|
252
|
+
|
|
253
|
+
## 录屏 `record.py`
|
|
254
|
+
|
|
255
|
+
> 输出为 **`.webm`**(Playwright 录屏的原生格式)。如需 mp4,请用 ffmpeg 后处理。
|
|
256
|
+
|
|
257
|
+
### 固定时长录屏
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
python3 <SkillDir>/scripts/record.py \
|
|
108
261
|
--url "https://example.com" \
|
|
109
|
-
--
|
|
110
|
-
--
|
|
262
|
+
--output "demo.webm" \
|
|
263
|
+
--viewport "1280,720" \
|
|
264
|
+
--duration 8000
|
|
111
265
|
```
|
|
112
266
|
|
|
113
|
-
|
|
267
|
+
### 等条件结束(推荐配合 max-duration 防卡死)
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# 等到 "加载完成" 元素出现就停
|
|
271
|
+
python3 <SkillDir>/scripts/record.py \
|
|
272
|
+
--url "https://example.com" \
|
|
273
|
+
--output "loaded.webm" \
|
|
274
|
+
--stop-when-selector "div.loaded" \
|
|
275
|
+
--max-duration 30000
|
|
276
|
+
|
|
277
|
+
# 等到 loading 转圈消失就停
|
|
278
|
+
python3 <SkillDir>/scripts/record.py \
|
|
279
|
+
--url "https://example.com" \
|
|
280
|
+
--output "spinner_done.webm" \
|
|
281
|
+
--stop-when-hidden ".spinner" \
|
|
282
|
+
--max-duration 30000
|
|
283
|
+
```
|
|
114
284
|
|
|
115
|
-
###
|
|
285
|
+
### 组合:先满足谁就停
|
|
116
286
|
|
|
117
287
|
```bash
|
|
118
|
-
python3 <SkillDir>/scripts/
|
|
288
|
+
python3 <SkillDir>/scripts/record.py \
|
|
119
289
|
--url "https://example.com" \
|
|
120
|
-
--
|
|
121
|
-
--
|
|
290
|
+
--output "race.webm" \
|
|
291
|
+
--duration 15000 \
|
|
292
|
+
--stop-when-selector ".done" \
|
|
293
|
+
--max-duration 20000
|
|
122
294
|
```
|
|
123
295
|
|
|
124
|
-
|
|
296
|
+
### 录屏前等页面就绪
|
|
125
297
|
|
|
126
|
-
|
|
298
|
+
```bash
|
|
299
|
+
python3 <SkillDir>/scripts/record.py \
|
|
300
|
+
--url "https://app.example.com" \
|
|
301
|
+
--output "after_login.webm" \
|
|
302
|
+
--storage-state "./auth.json" \
|
|
303
|
+
--wait-for-selector "#dashboard" \
|
|
304
|
+
--duration 6000
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 自动滚动录屏(从头划到尾)
|
|
127
308
|
|
|
128
|
-
|
|
309
|
+
```bash
|
|
310
|
+
python3 <SkillDir>/scripts/record.py \
|
|
311
|
+
--url "https://example.com" \
|
|
312
|
+
--output "scroll.webm" \
|
|
313
|
+
--viewport "1440,900" \
|
|
314
|
+
--scroll-through \
|
|
315
|
+
--scroll-step 50 \
|
|
316
|
+
--scroll-interval 60 \
|
|
317
|
+
--scroll-pause-top 1000 \
|
|
318
|
+
--scroll-pause-bottom 1500
|
|
319
|
+
```
|
|
129
320
|
|
|
130
|
-
|
|
131
|
-
|------|-------------|---------|
|
|
132
|
-
| `--url` | Target page URL (http/https). | required |
|
|
133
|
-
| `--mode` | `screenshot` / `scroll-video` / `record-video`. | `screenshot` |
|
|
134
|
-
| `-o` / `--output-dir` | Output directory. | unique system temp dir |
|
|
135
|
-
| `--width` | Viewport width (px). | `1280` |
|
|
136
|
-
| `--height` | Viewport height (px). | `720` |
|
|
137
|
-
| `--device-scale-factor` | Device pixel ratio (crisp / retina). | `2` |
|
|
138
|
-
| `--full-page` | Screenshot mode: capture the whole scrollable page. | off |
|
|
139
|
-
| `--selector` | Screenshot mode: capture only this CSS element. | none |
|
|
140
|
-
| `--fps` | Scroll / record video frame rate. | `30` |
|
|
141
|
-
| `--scroll-duration` | Seconds for the full top-to-bottom scroll. | `8` |
|
|
142
|
-
| `--browser` | `chromium` / `firefox` / `webkit`. | `chromium` |
|
|
143
|
-
| `--wait-until` | `load` / `domcontentloaded` / `networkidle`. | `networkidle` |
|
|
144
|
-
| `--wait-ms` | Extra wait after load before capture (ms). | `1500` |
|
|
145
|
-
| `--json-output` | Pipeline mode — JSON-only stdout. | off |
|
|
321
|
+
### 模板视频(快捷出片)
|
|
146
322
|
|
|
147
|
-
|
|
323
|
+
`templates/` 下提供参数化的 storyboard 模板,常见结构一行命令出片:
|
|
148
324
|
|
|
325
|
+
```bash
|
|
326
|
+
# 列出可用模板
|
|
327
|
+
python3 <SkillDir>/scripts/record.py --list-templates
|
|
328
|
+
|
|
329
|
+
# 用 github-repo-intro 模板录任意 GitHub 仓库
|
|
330
|
+
python3 <SkillDir>/scripts/record.py \
|
|
331
|
+
--template github-repo-intro \
|
|
332
|
+
--param repo_url=https://github.com/user/repo \
|
|
333
|
+
--output repo.webm
|
|
149
334
|
```
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
335
|
+
|
|
336
|
+
可重复 `--param key=value` 覆盖模板里的默认值(标签文字、颜色、缩放倍数等)。模板内 `_meta.params` 声明可接收的参数。
|
|
337
|
+
|
|
338
|
+
**当前模板**:
|
|
339
|
+
|
|
340
|
+
| 名字 | 说明 | 必填参数 |
|
|
341
|
+
|------|------|---------|
|
|
342
|
+
| `github-repo-intro` | GitHub 仓库三连:项目名红框 → star 页面 zoom → README 滚动 | `repo_url` |
|
|
343
|
+
| `github-readme-tour` | 标题卡 → 项目名 → 光标 hover star → README 滚动 → 结尾呼吁 | `repo_url` |
|
|
344
|
+
| `github-code-tour` | 跳转到文件 → 高亮行范围 → 字幕讲解 | `file_url` / `start_line` / `end_line` |
|
|
345
|
+
|
|
346
|
+
**新增模板**:在 `<SkillDir>/templates/` 下放一个 JSON,按 storyboard 格式写场景,里面用 `{{var_name}}` 占位。可选加 `_meta.params` 声明参数(标 `required: true` / `default: ...`)。占位单独成串时会自动转 int/float/bool(如 `"scale": "{{zoom_scale}}"` 渲染后是数字)。
|
|
347
|
+
|
|
348
|
+
### 自定义分镜(storyboard)
|
|
349
|
+
|
|
350
|
+
把一系列「场景」组合成一段视频,场景间用 overlay 淡入淡出过渡(**不会黑屏**)。
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
python3 <SkillDir>/scripts/record.py \
|
|
354
|
+
--url "https://github.com/user/repo" \
|
|
355
|
+
--output "story.webm" \
|
|
356
|
+
--viewport "1440,900" \
|
|
357
|
+
--storyboard story.json
|
|
154
358
|
```
|
|
155
359
|
|
|
156
|
-
|
|
360
|
+
`story.json` 示例:
|
|
157
361
|
|
|
158
362
|
```json
|
|
159
363
|
{
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
|
|
364
|
+
"url": "https://github.com/user/repo",
|
|
365
|
+
"viewport": [1440, 900],
|
|
366
|
+
"waitForReadySelectors": ["article.markdown-body"],
|
|
367
|
+
"settleMs": 1200,
|
|
368
|
+
"transition": { "fadeOutMs": 320, "gapMs": 180 },
|
|
369
|
+
"scenes": [
|
|
370
|
+
{
|
|
371
|
+
"type": "highlight",
|
|
372
|
+
"selector": "strong[itemprop=\"name\"] a",
|
|
373
|
+
"color": "#ff3b30",
|
|
374
|
+
"lineWidth": 5,
|
|
375
|
+
"padding": 10,
|
|
376
|
+
"label": "项目名称",
|
|
377
|
+
"duration": 3000
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"type": "zoom",
|
|
381
|
+
"target": "page",
|
|
382
|
+
"selector": "#repo-stars-counter-star",
|
|
383
|
+
"scale": 2.4,
|
|
384
|
+
"rampInMs": 900,
|
|
385
|
+
"holdMs": 2200,
|
|
386
|
+
"rampOutMs": 700,
|
|
387
|
+
"label": "⭐ Star 数量"
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
"type": "scroll",
|
|
391
|
+
"fromSelector": "article.markdown-body",
|
|
392
|
+
"step": 50,
|
|
393
|
+
"interval": 70,
|
|
394
|
+
"duration": 10000,
|
|
395
|
+
"holdAtEnd": 800
|
|
396
|
+
}
|
|
165
397
|
]
|
|
166
398
|
}
|
|
167
399
|
```
|
|
168
400
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
-
|
|
178
|
-
-
|
|
179
|
-
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
-
|
|
183
|
-
-
|
|
401
|
+
**场景类型**:
|
|
402
|
+
|
|
403
|
+
*视觉强调*
|
|
404
|
+
- `highlight` — 元素红框 + 标签,`padding` / `lineWidth` / `color` / `duration`
|
|
405
|
+
- `focus` — 周围暗化(spotlight)+ 元素描边 + 标签
|
|
406
|
+
- `zoom` — 放大动画
|
|
407
|
+
- `target: "element"` (默认) — 缩放目标元素本身(弹性曲线)
|
|
408
|
+
- `target: "page"` — 像浏览器 zoom 一样整个页面以目标元素中心放大
|
|
409
|
+
- `scale` / `rampInMs` / `rampOutMs` / `holdMs` / `dim` / `label` / `color`
|
|
410
|
+
- `scroll` — 滚动到目标。`fromSelector` 起点、`toSelector` 终点、`step` / `interval` / `duration` / `holdAtEnd`
|
|
411
|
+
- `wait` — 单纯停顿 `duration`
|
|
412
|
+
|
|
413
|
+
*交互模拟(虚拟光标)*
|
|
414
|
+
- `click` — 光标飞向元素 → 涟漪 → 真实触发 `el.click()`。`moveMs` / `preHoldMs` / `postHoldMs` / `rippleMs` / `color` / `realClick`(默认 true,可设 false 只动画不点)
|
|
415
|
+
- `type` — 光标飞向输入框 → focus → 逐字打字。`text` / `delay`(ms/字) / `clearFirst` / `moveCursor`
|
|
416
|
+
- `hover` — 光标移到元素并触发原生 hover,常用于悬出 tooltip / hover card。`moveMs` / `holdMs`
|
|
417
|
+
|
|
418
|
+
*注释表达*
|
|
419
|
+
- `arrow` — 从一个锚点画 SVG 弧线箭头指向另一个锚点。锚点 `from` / `to` 形如 `{selector, side}`(side: center/left/right/top/bottom)或 `{x, y}`。`color` / `lineWidth` / `label` / `duration`
|
|
420
|
+
- `sequence` — 多个 selector 顺序出 ①②③ 圆形 badge + 红框 + 标签。`items: [{selector, label}, ...]` / `stepMs` 控制每步间隔 / `color` / `holdMs`
|
|
421
|
+
- `caption` — 顶部/底部滑入字幕条。`text` / `position: top|bottom` / `background` / `color` / `fontSize` / `duration`
|
|
422
|
+
- `title-card` — 全屏开场/结尾大标题卡。`title` / `subtitle`(可选) / `background` / `accent` / `duration`
|
|
423
|
+
- `redact` — 局部打码:blur / pixelate / 实色。`selectors: [...]` 或 `selector` / `mode: "blur" | "pixelate" | "solid"` / `color`(实色时) / `duration`
|
|
424
|
+
|
|
425
|
+
*GitHub 专属*
|
|
426
|
+
- `code-lines` — 高亮连续代码行范围(默认匹配新版 React blob `[data-line-number="{n}"]`;老版 blob 表格用 `linePattern: "#LC{n}"`)。`startLine` / `endLine` / `linePattern` / `color` / `label` / `duration`
|
|
427
|
+
|
|
428
|
+
**自动裁剪**:storyboard 模式录制时会等待页面真正稳定(networkidle + skeleton 消失),并在事后用 ffmpeg 帧精度裁掉开头加载段,最终视频长度 ≈ 各场景总时长。
|
|
429
|
+
|
|
430
|
+
### record.py 参数
|
|
431
|
+
|
|
432
|
+
| 参数 | 说明 | 默认 |
|
|
433
|
+
|------|------|------|
|
|
434
|
+
| `-u` / `--url` | 目标 URL(必填) | — |
|
|
435
|
+
| `-o` / `--output` | 本地输出 `.webm` 路径 | `recording.webm` |
|
|
436
|
+
| `-b` / `--browser` | `chromium` / `firefox` / `webkit`(建议 chromium) | `chromium` |
|
|
437
|
+
| `--device` | 设备模拟 | 无 |
|
|
438
|
+
| `--viewport` | `"宽,高"` | 无 |
|
|
439
|
+
| `--duration` | 固定录制时长(ms) | 无 |
|
|
440
|
+
| `--stop-when-selector` | 选择器出现就停 | 无 |
|
|
441
|
+
| `--stop-when-hidden` | 选择器消失就停 | 无 |
|
|
442
|
+
| `--max-duration` | 条件模式安全上限(ms) | 60000 |
|
|
443
|
+
| `--scroll-through` | 自动从顶部滚到底部 | 关 |
|
|
444
|
+
| `--scroll-step` | 每步像素 | 60 |
|
|
445
|
+
| `--scroll-interval` | 每步间隔(ms) | 50 |
|
|
446
|
+
| `--scroll-pause-top` | 顶部停留(ms) | 800 |
|
|
447
|
+
| `--scroll-pause-bottom` | 底部停留(ms) | 1200 |
|
|
448
|
+
| `--storyboard` | 分镜 JSON 文件路径 | 无 |
|
|
449
|
+
| `--template` | 模板名(templates/<name>.json);与 `--storyboard` 互斥 | 无 |
|
|
450
|
+
| `--param` | 模板参数 `key=value`,可重复 | 无 |
|
|
451
|
+
| `--list-templates` | 列出可用模板并退出 | — |
|
|
452
|
+
| `--wait-for-selector` | 开始录前等待出现 | 无 |
|
|
453
|
+
| `--wait-for-timeout` | 开始录前固定等待(ms) | 无 |
|
|
454
|
+
| `--color-scheme` | prefers-color-scheme | 无 |
|
|
455
|
+
| `--user-agent` | 覆盖 UA | 无 |
|
|
456
|
+
| `--timeout` | Playwright 全局超时(ms) | 无 |
|
|
457
|
+
| `--ignore-https-errors` | 忽略证书错误 | 关 |
|
|
458
|
+
| `--storage-state` | storageState JSON 文件 | 无 |
|
|
459
|
+
| `--cookies` | cookies JSON 字符串或文件 | 无 |
|
|
460
|
+
|
|
461
|
+
至少需提供 `--duration` / `--stop-when-selector` / `--stop-when-hidden` / `--scroll-through` / `--storyboard` / `--template` 之一;组合使用时**先满足谁就停**,同时受 `--max-duration` 兜底。模板 / storyboard JSON 可自带 `url`,此时可省略 `--url`。
|
|
462
|
+
|
|
463
|
+
## 错误处理
|
|
464
|
+
|
|
465
|
+
- **首次跑慢**:脚本自动 `pip install playwright` + `playwright install chromium`,耐心等一次即可。
|
|
466
|
+
- **`Cannot find module 'playwright'` / `ModuleNotFoundError: playwright`**:bootstrap 没装上,手动跑 `pip install playwright && playwright install chromium`。
|
|
467
|
+
- **`Executable doesn't exist`**:浏览器内核没装,跑 `playwright install chromium`(脚本通常会自动触发)。
|
|
468
|
+
- **`Timeout ... exceeded`**:拉大 `--timeout`、`--wait-for-timeout`,或换更稳的 `--wait-for-selector`。
|
|
469
|
+
- **截屏空白 / 没渲染完**:加 `--wait-for-selector` 等业务关键元素;纯动画类用 `--wait-for-timeout`。
|
|
470
|
+
- **`selector "X" has no bounding box`**:元素存在但不可见 / 尺寸为 0;先用 `--wait-for-selector` 等可见。
|
|
471
|
+
- **登录态失效**:重新导出 `storageState` 或更新 `cookies` JSON;`domain` / `path` 必须匹配。
|
|
472
|
+
- **HTTPS 证书报错**:测试环境可加 `--ignore-https-errors`。
|
|
473
|
+
- **录屏文件没产生**:检查 `--output` 后缀是否 `.webm`;查看 stderr 的 `stop reason`。
|
|
474
|
+
- **storyboard 开头还有加载残影**:装 ffmpeg;或加大 `settleMs` / `waitForReadySelectors`。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""media-screenshot internal package.
|
|
2
|
+
|
|
3
|
+
Public surface used by the entry-point scripts. Anything else under this
|
|
4
|
+
package is implementation detail.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from . import cli_args, scenes, template, trim
|
|
9
|
+
from .recording import do_record
|
|
10
|
+
from .screenshot import do_screenshot
|
|
11
|
+
from .storyboard import do_storyboard
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"cli_args",
|
|
15
|
+
"do_record",
|
|
16
|
+
"do_screenshot",
|
|
17
|
+
"do_storyboard",
|
|
18
|
+
"scenes",
|
|
19
|
+
"template",
|
|
20
|
+
"trim",
|
|
21
|
+
]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Auto-install playwright + chromium on first run."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _pip_install(pkg: str) -> None:
|
|
9
|
+
print(f"[bootstrap] pip install {pkg} ...", file=sys.stderr)
|
|
10
|
+
subprocess.check_call(
|
|
11
|
+
[sys.executable, "-m", "pip", "install", "--quiet", pkg]
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _ensure_playwright_pkg() -> None:
|
|
16
|
+
try:
|
|
17
|
+
import playwright.sync_api # noqa: F401
|
|
18
|
+
return
|
|
19
|
+
except ImportError:
|
|
20
|
+
pass
|
|
21
|
+
_pip_install("playwright")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def ensure_chromium() -> None:
|
|
25
|
+
"""Install the chromium browser via `playwright install`."""
|
|
26
|
+
print("[bootstrap] playwright install chromium ...", file=sys.stderr)
|
|
27
|
+
subprocess.check_call(
|
|
28
|
+
[sys.executable, "-m", "playwright", "install", "chromium"]
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def ensure_runtime() -> None:
|
|
33
|
+
"""Make sure the playwright pip package is importable."""
|
|
34
|
+
_ensure_playwright_pkg()
|