@spark-apps/quickpeek 1.2.0 → 1.2.2
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 +204 -204
- package/dist/highlight.css +15 -15
- package/dist/index.d.mts +79 -3
- package/dist/index.mjs +284 -65
- package/dist/mcp-tools.mjs +1861 -872
- package/dist/qp.js +1606 -838
- package/dist/{scraping-BK8pIJhm.d.mts → scraping-BgepklP3.d.mts} +51 -6
- package/dist/web.d.mts +42 -2
- package/dist/web.mjs +174 -37
- package/mcp.mjs +28 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,204 +1,204 @@
|
|
|
1
|
-
[license-link]: ./LICENSE
|
|
2
|
-
[privacy-link]: ./PRIVACY.md
|
|
3
|
-
[discord-link]: https://discord.gg/
|
|
4
|
-
[stars-link]: ../../stargazers
|
|
5
|
-
[issues-link]: ../../issues
|
|
6
|
-
|
|
7
|
-
<div align="center">
|
|
8
|
-
|
|
9
|
-
<img src=imgs/logo.png>
|
|
10
|
-
|
|
11
|
-
**Demo videos for your web app with AI**
|
|
12
|
-
|
|
13
|
-
*Because Tutorial Videos are Overrated!*
|
|
14
|
-
|
|
15
|
-
[](https://www.npmjs.com/package/@spark-apps/quickpeek)
|
|
16
|
-
[][license-link]
|
|
17
|
-
[][discord-link]
|
|
18
|
-
[][stars-link]
|
|
19
|
-
|
|
20
|
-
</div>
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Quick Start
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install -g @spark-apps/quickpeek
|
|
28
|
-
qp localhost:3000
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
**Requirements:** [ffmpeg](https://ffmpeg.org/download.html), [Groq API key](https://console.groq.com/keys) (free)
|
|
32
|
-
|
|
33
|
-
## Features
|
|
34
|
-
|
|
35
|
-
| Feature | Description |
|
|
36
|
-
|---------|-------------|
|
|
37
|
-
| **AI Planning** | Groq AI analyzes your app and generates demo steps |
|
|
38
|
-
| **Script Mode** | Provide your own narration script, AI maps it to UI actions |
|
|
39
|
-
| **Capture Mode** | Record your own interactions → replayable plan.json |
|
|
40
|
-
| **Voice Over** | Free Edge TTS narration in 60+ languages |
|
|
41
|
-
| **Karaoke Captions** | Word-by-word highlighted subtitles |
|
|
42
|
-
| **Background Music** | Optional music with fade in/out |
|
|
43
|
-
| **Smart Zoom** | Per-step zoom for focused demos |
|
|
44
|
-
| **Chrome Extensions** | Record demos for Chrome extensions |
|
|
45
|
-
|
|
46
|
-
## Examples
|
|
47
|
-
|
|
48
|
-
### Basic — AI generates the plan
|
|
49
|
-
|
|
50
|
-
```bash
|
|
51
|
-
qp localhost:3000
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### Script mode — you write the narration
|
|
55
|
-
|
|
56
|
-
```bash
|
|
57
|
-
qp localhost:3000 --script narration.txt
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
Script file format (one caption per line, `#` for comments):
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
# My app demo
|
|
64
|
-
We start on the dashboard — your main workspace.
|
|
65
|
-
Let's search for a customer by typing their name.
|
|
66
|
-
Click the result to open their profile.
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Capture mode — record your own interactions
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
qp capture localhost:3000
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Browse the app freely, press Enter when done. QuickPeek converts your clicks, typing, and scrolls into a `plan.json` that can be replayed as a polished video.
|
|
76
|
-
|
|
77
|
-
### With options
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
qp localhost:3000 lang=es -d "A todo app for managing daily tasks"
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Chrome Extensions
|
|
84
|
-
|
|
85
|
-
Record demos for Chrome extensions using the `chrome:` prefix:
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
qp chrome:your-extension-id
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
QuickPeek will automatically:
|
|
92
|
-
1. Find the extension in your Chrome installation
|
|
93
|
-
2. Load and analyze the extension popup UI
|
|
94
|
-
3. Generate a demo plan with AI
|
|
95
|
-
|
|
96
|
-
The popup URL is detected from the extension's manifest.
|
|
97
|
-
|
|
98
|
-
| Option | Description |
|
|
99
|
-
|--------|-------------|
|
|
100
|
-
| `lang` | Voice language (en, es, ar, zh...) |
|
|
101
|
-
| `-d, --description` | App description to guide AI |
|
|
102
|
-
| `-s, --script` | Path to narration script file |
|
|
103
|
-
| `video.width/height` | Resolution (default: 1080x1920) |
|
|
104
|
-
| `video.quality` | Quality 0-1 (default: 0.5) |
|
|
105
|
-
| `music.path` | Background music file |
|
|
106
|
-
| `music.volume` | Music volume 0-1 (default: 0.3) |
|
|
107
|
-
| `output.dir` | Output directory (default: ./demo) |
|
|
108
|
-
|
|
109
|
-
Config is auto-generated on first run. Edit `quickpeek.config.json` to customize.
|
|
110
|
-
|
|
111
|
-
<details>
|
|
112
|
-
<summary><strong>Supported Languages</strong></summary>
|
|
113
|
-
|
|
114
|
-
| Code | Language | Code | Language |
|
|
115
|
-
|------|----------|------|----------|
|
|
116
|
-
| `en` | English | `ar` | Arabic |
|
|
117
|
-
| `es` | Spanish | `fr` | French |
|
|
118
|
-
| `de` | German | `zh` | Chinese |
|
|
119
|
-
| `ja` | Japanese | `ko` | Korean |
|
|
120
|
-
| `pt` | Portuguese | `hi` | Hindi |
|
|
121
|
-
| `it` | Italian | `ru` | Russian |
|
|
122
|
-
|
|
123
|
-
See `src/voices.ts` for all 60+ supported languages.
|
|
124
|
-
|
|
125
|
-
</details>
|
|
126
|
-
|
|
127
|
-
<details>
|
|
128
|
-
<summary><strong>Caption Style</strong></summary>
|
|
129
|
-
|
|
130
|
-
Edit `captions.css` (auto-generated) to customize:
|
|
131
|
-
|
|
132
|
-

|
|
133
|
-
|
|
134
|
-
```css
|
|
135
|
-
.caption {
|
|
136
|
-
font-family: Arial, sans-serif;
|
|
137
|
-
-webkit-text-stroke: 3px #000000;
|
|
138
|
-
}
|
|
139
|
-
.caption .regular {
|
|
140
|
-
font-size: 56px;
|
|
141
|
-
color: #FFFFFF;
|
|
142
|
-
}
|
|
143
|
-
.caption .highlight {
|
|
144
|
-
font-size: 64px;
|
|
145
|
-
color: #FFFF00;
|
|
146
|
-
}
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
</details>
|
|
150
|
-
|
|
151
|
-
## Plan Actions
|
|
152
|
-
|
|
153
|
-
Edit `demo/plan.json` to customize your demo. Each step uses one of these actions:
|
|
154
|
-
|
|
155
|
-
| Action | Target | Value | Description |
|
|
156
|
-
|--------|--------|-------|-------------|
|
|
157
|
-
| `wait` | - | - | Pause for narration (intro/outro) |
|
|
158
|
-
| `click` | `"button text"` | - | Click button/link |
|
|
159
|
-
| `click-N` | `"button text"` | - | Click N times (e.g., `click-2`, `click-3`) |
|
|
160
|
-
| `type` | `input[name="field"]` | `"text to type"` | Type into input field |
|
|
161
|
-
| `upload` | `input[type="file"]` | `"path/to/file"` | Upload file to form |
|
|
162
|
-
| `select` | `select[name="field"]` | `"option text"` | Select dropdown option |
|
|
163
|
-
| `check` | `input[type="checkbox"]` | - | Toggle checkbox |
|
|
164
|
-
| `drag` | `input[type="range"]` | `"0"`-`"100"` | Drag slider to value |
|
|
165
|
-
| `drag` | `canvas` | `"around"` | Full 360° rotation (returns to start) |
|
|
166
|
-
| `drag` | `canvas` | `"rotate"` | Rotate ~270° (stays at new angle) |
|
|
167
|
-
| `drag` | `canvas` | `"rotate:90"` | Rotate specific angle (circular) |
|
|
168
|
-
| `drag` | `canvas` | `"rotate:x-90"` | Rotate on X axis (horizontal drag) |
|
|
169
|
-
| `drag` | `canvas` | `"rotate:y45"` | Rotate on Y axis (vertical drag) |
|
|
170
|
-
| `drag` | - | `"left"` `"right"` `"up"` `"down"` | Directional drag |
|
|
171
|
-
| `scroll` | - | `"up"` `"down"` `"bottom"` | Scroll page |
|
|
172
|
-
| `scroll` | - | `"-10"` to `"10"` | Zoom camera (negative=out, positive=in) |
|
|
173
|
-
| `media` | `"scale"` or `"center"` | `"path/to/file"` | Display image/video fullscreen |
|
|
174
|
-
| `showDownload` | - | - | Show the last downloaded file |
|
|
175
|
-
|
|
176
|
-
**Target shortcuts:** For buttons and links, use simplified text like `"download"` or `"extract frame"` instead of CSS selectors.
|
|
177
|
-
|
|
178
|
-
## Output
|
|
179
|
-
|
|
180
|
-
| File | Description |
|
|
181
|
-
|------|-------------|
|
|
182
|
-
| `demo/demo.mp4` | Final video |
|
|
183
|
-
| `demo/plan.json` | Editable script (re-run to apply changes) |
|
|
184
|
-
|
|
185
|
-
> `plan.json` is also accepted by [VidLet](https://vidlet.app)'s `create_project`
|
|
186
|
-
> MCP tool, which turns the steps into a `.vidlet` timeline project for further
|
|
187
|
-
> editing and narration.
|
|
188
|
-
|
|
189
|
-
## 🌱 Support & Contributions
|
|
190
|
-
|
|
191
|
-
⭐ **Star the repo** & I power up like Mario 🍄
|
|
192
|
-
☕ **Devs run on coffee** - [Buy me one?][coffee-link]
|
|
193
|
-
💖 **Sponsor** [Your support][stars-link] helps maintain and improve the tool<br>
|
|
194
|
-
💰 **Crypto tips welcome** - [Tip in crypto](https://tip.md/muammar-yacoob)
|
|
195
|
-
🤝 **Contributions are welcome** - [🍴 Fork][fork-link], improve, PR!
|
|
196
|
-
🎥 **Need help?** <img src="https://img.icons8.com/color/20/youtube-play.png" alt="YouTube" width="20" height="20" style="vertical-align: middle;"> [Setup Tutorial][vid-link] • <img src="https://img.icons8.com/color/20/discord--v2.png" alt="Discord" width="20" height="20" style="vertical-align: middle;"> [Join Discord][discord-link]
|
|
197
|
-
|
|
198
|
-
<div align="center">
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
MIT License - Made with ☕ by [Spark Apps](https://github.com/muammar-yacoob)
|
|
203
|
-
|
|
204
|
-
</div>
|
|
1
|
+
[license-link]: ./LICENSE
|
|
2
|
+
[privacy-link]: ./PRIVACY.md
|
|
3
|
+
[discord-link]: https://discord.gg/mAjHWE3mSp
|
|
4
|
+
[stars-link]: ../../stargazers
|
|
5
|
+
[issues-link]: ../../issues
|
|
6
|
+
|
|
7
|
+
<div align="center">
|
|
8
|
+
|
|
9
|
+
<img src=imgs/logo.png>
|
|
10
|
+
|
|
11
|
+
**Demo videos for your web app with AI**
|
|
12
|
+
|
|
13
|
+
*Because Tutorial Videos are Overrated!*
|
|
14
|
+
|
|
15
|
+
[](https://www.npmjs.com/package/@spark-apps/quickpeek)
|
|
16
|
+
[][license-link]
|
|
17
|
+
[][discord-link]
|
|
18
|
+
[][stars-link]
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install -g @spark-apps/quickpeek
|
|
28
|
+
qp localhost:3000
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Requirements:** [ffmpeg](https://ffmpeg.org/download.html), [Groq API key](https://console.groq.com/keys) (free)
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
| Feature | Description |
|
|
36
|
+
|---------|-------------|
|
|
37
|
+
| **AI Planning** | Groq AI analyzes your app and generates demo steps |
|
|
38
|
+
| **Script Mode** | Provide your own narration script, AI maps it to UI actions |
|
|
39
|
+
| **Capture Mode** | Record your own interactions → replayable plan.json |
|
|
40
|
+
| **Voice Over** | Free Edge TTS narration in 60+ languages |
|
|
41
|
+
| **Karaoke Captions** | Word-by-word highlighted subtitles |
|
|
42
|
+
| **Background Music** | Optional music with fade in/out |
|
|
43
|
+
| **Smart Zoom** | Per-step zoom for focused demos |
|
|
44
|
+
| **Chrome Extensions** | Record demos for Chrome extensions |
|
|
45
|
+
|
|
46
|
+
## Examples
|
|
47
|
+
|
|
48
|
+
### Basic — AI generates the plan
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
qp localhost:3000
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Script mode — you write the narration
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
qp localhost:3000 --script narration.txt
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Script file format (one caption per line, `#` for comments):
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
# My app demo
|
|
64
|
+
We start on the dashboard — your main workspace.
|
|
65
|
+
Let's search for a customer by typing their name.
|
|
66
|
+
Click the result to open their profile.
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Capture mode — record your own interactions
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
qp capture localhost:3000
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Browse the app freely, press Enter when done. QuickPeek converts your clicks, typing, and scrolls into a `plan.json` that can be replayed as a polished video.
|
|
76
|
+
|
|
77
|
+
### With options
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
qp localhost:3000 lang=es -d "A todo app for managing daily tasks"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Chrome Extensions
|
|
84
|
+
|
|
85
|
+
Record demos for Chrome extensions using the `chrome:` prefix:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
qp chrome:your-extension-id
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
QuickPeek will automatically:
|
|
92
|
+
1. Find the extension in your Chrome installation
|
|
93
|
+
2. Load and analyze the extension popup UI
|
|
94
|
+
3. Generate a demo plan with AI
|
|
95
|
+
|
|
96
|
+
The popup URL is detected from the extension's manifest.
|
|
97
|
+
|
|
98
|
+
| Option | Description |
|
|
99
|
+
|--------|-------------|
|
|
100
|
+
| `lang` | Voice language (en, es, ar, zh...) |
|
|
101
|
+
| `-d, --description` | App description to guide AI |
|
|
102
|
+
| `-s, --script` | Path to narration script file |
|
|
103
|
+
| `video.width/height` | Resolution (default: 1080x1920) |
|
|
104
|
+
| `video.quality` | Quality 0-1 (default: 0.5) |
|
|
105
|
+
| `music.path` | Background music file |
|
|
106
|
+
| `music.volume` | Music volume 0-1 (default: 0.3) |
|
|
107
|
+
| `output.dir` | Output directory (default: ./demo) |
|
|
108
|
+
|
|
109
|
+
Config is auto-generated on first run. Edit `quickpeek.config.json` to customize.
|
|
110
|
+
|
|
111
|
+
<details>
|
|
112
|
+
<summary><strong>Supported Languages</strong></summary>
|
|
113
|
+
|
|
114
|
+
| Code | Language | Code | Language |
|
|
115
|
+
|------|----------|------|----------|
|
|
116
|
+
| `en` | English | `ar` | Arabic |
|
|
117
|
+
| `es` | Spanish | `fr` | French |
|
|
118
|
+
| `de` | German | `zh` | Chinese |
|
|
119
|
+
| `ja` | Japanese | `ko` | Korean |
|
|
120
|
+
| `pt` | Portuguese | `hi` | Hindi |
|
|
121
|
+
| `it` | Italian | `ru` | Russian |
|
|
122
|
+
|
|
123
|
+
See `src/voices.ts` for all 60+ supported languages.
|
|
124
|
+
|
|
125
|
+
</details>
|
|
126
|
+
|
|
127
|
+
<details>
|
|
128
|
+
<summary><strong>Caption Style</strong></summary>
|
|
129
|
+
|
|
130
|
+
Edit `captions.css` (auto-generated) to customize:
|
|
131
|
+
|
|
132
|
+

|
|
133
|
+
|
|
134
|
+
```css
|
|
135
|
+
.caption {
|
|
136
|
+
font-family: Arial, sans-serif;
|
|
137
|
+
-webkit-text-stroke: 3px #000000;
|
|
138
|
+
}
|
|
139
|
+
.caption .regular {
|
|
140
|
+
font-size: 56px;
|
|
141
|
+
color: #FFFFFF;
|
|
142
|
+
}
|
|
143
|
+
.caption .highlight {
|
|
144
|
+
font-size: 64px;
|
|
145
|
+
color: #FFFF00;
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
</details>
|
|
150
|
+
|
|
151
|
+
## Plan Actions
|
|
152
|
+
|
|
153
|
+
Edit `demo/plan.json` to customize your demo. Each step uses one of these actions:
|
|
154
|
+
|
|
155
|
+
| Action | Target | Value | Description |
|
|
156
|
+
|--------|--------|-------|-------------|
|
|
157
|
+
| `wait` | - | - | Pause for narration (intro/outro) |
|
|
158
|
+
| `click` | `"button text"` | - | Click button/link |
|
|
159
|
+
| `click-N` | `"button text"` | - | Click N times (e.g., `click-2`, `click-3`) |
|
|
160
|
+
| `type` | `input[name="field"]` | `"text to type"` | Type into input field |
|
|
161
|
+
| `upload` | `input[type="file"]` | `"path/to/file"` | Upload file to form |
|
|
162
|
+
| `select` | `select[name="field"]` | `"option text"` | Select dropdown option |
|
|
163
|
+
| `check` | `input[type="checkbox"]` | - | Toggle checkbox |
|
|
164
|
+
| `drag` | `input[type="range"]` | `"0"`-`"100"` | Drag slider to value |
|
|
165
|
+
| `drag` | `canvas` | `"around"` | Full 360° rotation (returns to start) |
|
|
166
|
+
| `drag` | `canvas` | `"rotate"` | Rotate ~270° (stays at new angle) |
|
|
167
|
+
| `drag` | `canvas` | `"rotate:90"` | Rotate specific angle (circular) |
|
|
168
|
+
| `drag` | `canvas` | `"rotate:x-90"` | Rotate on X axis (horizontal drag) |
|
|
169
|
+
| `drag` | `canvas` | `"rotate:y45"` | Rotate on Y axis (vertical drag) |
|
|
170
|
+
| `drag` | - | `"left"` `"right"` `"up"` `"down"` | Directional drag |
|
|
171
|
+
| `scroll` | - | `"up"` `"down"` `"bottom"` | Scroll page |
|
|
172
|
+
| `scroll` | - | `"-10"` to `"10"` | Zoom camera (negative=out, positive=in) |
|
|
173
|
+
| `media` | `"scale"` or `"center"` | `"path/to/file"` | Display image/video fullscreen |
|
|
174
|
+
| `showDownload` | - | - | Show the last downloaded file |
|
|
175
|
+
|
|
176
|
+
**Target shortcuts:** For buttons and links, use simplified text like `"download"` or `"extract frame"` instead of CSS selectors.
|
|
177
|
+
|
|
178
|
+
## Output
|
|
179
|
+
|
|
180
|
+
| File | Description |
|
|
181
|
+
|------|-------------|
|
|
182
|
+
| `demo/demo.mp4` | Final video |
|
|
183
|
+
| `demo/plan.json` | Editable script (re-run to apply changes) |
|
|
184
|
+
|
|
185
|
+
> `plan.json` is also accepted by [VidLet](https://vidlet.app)'s `create_project`
|
|
186
|
+
> MCP tool, which turns the steps into a `.vidlet` timeline project for further
|
|
187
|
+
> editing and narration.
|
|
188
|
+
|
|
189
|
+
## 🌱 Support & Contributions
|
|
190
|
+
|
|
191
|
+
⭐ **Star the repo** & I power up like Mario 🍄
|
|
192
|
+
☕ **Devs run on coffee** - [Buy me one?][coffee-link]
|
|
193
|
+
💖 **Sponsor** [Your support][stars-link] helps maintain and improve the tool<br>
|
|
194
|
+
💰 **Crypto tips welcome** - [Tip in crypto](https://tip.md/muammar-yacoob)
|
|
195
|
+
🤝 **Contributions are welcome** - [🍴 Fork][fork-link], improve, PR!
|
|
196
|
+
🎥 **Need help?** <img src="https://img.icons8.com/color/20/youtube-play.png" alt="YouTube" width="20" height="20" style="vertical-align: middle;"> [Setup Tutorial][vid-link] • <img src="https://img.icons8.com/color/20/discord--v2.png" alt="Discord" width="20" height="20" style="vertical-align: middle;"> [Join Discord][discord-link]
|
|
197
|
+
|
|
198
|
+
<div align="center">
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
MIT License - Made with ☕ by [Spark Apps](https://github.com/muammar-yacoob)
|
|
203
|
+
|
|
204
|
+
</div>
|
package/dist/highlight.css
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
#qp-highlight-overlay {
|
|
2
|
-
position: fixed;
|
|
3
|
-
inset: 0;
|
|
4
|
-
background: rgba(0, 0, 0, 0.5);
|
|
5
|
-
z-index: 999998;
|
|
6
|
-
pointer-events: none;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
[data-qp-highlight] {
|
|
10
|
-
position: relative !important;
|
|
11
|
-
z-index: 999999 !important;
|
|
12
|
-
outline: 3px solid #ffd700 !important;
|
|
13
|
-
outline-offset: 2px !important;
|
|
14
|
-
border-radius: 8px !important;
|
|
15
|
-
}
|
|
1
|
+
#qp-highlight-overlay {
|
|
2
|
+
position: fixed;
|
|
3
|
+
inset: 0;
|
|
4
|
+
background: rgba(0, 0, 0, 0.5);
|
|
5
|
+
z-index: 999998;
|
|
6
|
+
pointer-events: none;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
[data-qp-highlight] {
|
|
10
|
+
position: relative !important;
|
|
11
|
+
z-index: 999999 !important;
|
|
12
|
+
outline: 3px solid #ffd700 !important;
|
|
13
|
+
outline-offset: 2px !important;
|
|
14
|
+
border-radius: 8px !important;
|
|
15
|
+
}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { U as UserTier, C as Config } from './scraping-
|
|
2
|
-
export { A as AIError, a as AIResponse, b as AIResult, c as
|
|
1
|
+
import { U as UserTier, C as Config } from './scraping-BgepklP3.mjs';
|
|
2
|
+
export { A as AIError, a as AIResponse, b as AIResult, c as CLI_BACKOFF_MS, d as CONFIG_FILE, e as CaptionStyle, f as CaptionWordStyle, g as ChatOptions, D as DEFAULT_CAPTIONS, h as DEFAULT_CONFIG, E as EXCLUDED_LINK_PATTERNS, i as ElementInfo, j as ElementType, F as FEATURES, H as HighlightMode, I as INTERACTIVE_SELECTORS, P as Plan, R as RateLimitInfo, k as RetryNotice, S as SERVER_BACKOFF_MS, l as SparkStatus, m as SparkSubscription, n as SparkTrial, o as Step, p as SuggestedAction, T as Tier, V as VERSION, q as buildSystemPrompt, r as buildUserPrompt, s as callAI, t as callAIViaRelay, u as crawlPage, v as getErrorMessage, w as getLanguageName, x as getStatus, y as getStatusCached, z as getTierByEmail, B as hasAccess, G as hasTrialRemaining, J as idSelector, K as isCanceling, L as isExcludedLink, M as isPaid, N as isVerified, O as normalizeUrl, Q as parseAIPlanResponse, W as parsePartial, X as pricingUrl, Y as rgbaToHex, Z as shouldSkipLink, _ as showPaywall, $ as toTitleCase } from './scraping-BgepklP3.mjs';
|
|
3
3
|
export { WIDE_VOICES as LANGUAGE_VOICES, hexToAss as hexToASS, windowsDrivePathToWsl as windowsPathToWSL } from '@spark-apps/video-kit';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -124,9 +124,27 @@ declare function mapTimestampsAfterCompression(originalTimestampsSeconds: number
|
|
|
124
124
|
* Run ffprobe to get media duration in milliseconds
|
|
125
125
|
*/
|
|
126
126
|
declare function getMediaDuration(filePath: string): Promise<number>;
|
|
127
|
+
/**
|
|
128
|
+
* Report the codec of a file's first audio stream, or '' if it cannot be read
|
|
129
|
+
*/
|
|
130
|
+
declare function getAudioCodec(filePath: string): Promise<string>;
|
|
131
|
+
/**
|
|
132
|
+
* A WAV whose stream is not PCM was written by the old stream-copy concat and
|
|
133
|
+
* misreports its duration, so it must never be reused - see concatMedia.
|
|
134
|
+
*/
|
|
135
|
+
declare function isHonestWav(filePath: string): Promise<boolean>;
|
|
127
136
|
/**
|
|
128
137
|
* Concatenate audio files using ffmpeg concat demuxer
|
|
138
|
+
*
|
|
139
|
+
* The segments are MP3 (edge-tts clips and generated silence). Stream-copying
|
|
140
|
+
* them into a WAV container stores MP3 packets behind a PCM-style header, so
|
|
141
|
+
* every later ffprobe derives the duration from the PCM byte rate and reports
|
|
142
|
+
* a wildly inflated length - a 39.7s voiceover probed as 57.6s. That bogus
|
|
143
|
+
* figure then drives step alignment and the compose filters, which is why the
|
|
144
|
+
* voiceover ran far past the end of the video. Decode to real PCM whenever the
|
|
145
|
+
* output is WAV so the duration is honest; other containers can still copy.
|
|
129
146
|
*/
|
|
147
|
+
declare function buildConcatArgs(listPath: string, output: string): string[];
|
|
130
148
|
declare function concatMedia(listPath: string, output: string): Promise<void>;
|
|
131
149
|
/**
|
|
132
150
|
* Generate silence audio file of specified duration
|
|
@@ -172,6 +190,64 @@ declare function buildStepTransitions(steps: {
|
|
|
172
190
|
*/
|
|
173
191
|
declare function applyTransitions(opts: ApplyTransitionsOptions): Promise<void>;
|
|
174
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Deterministic repair for JSON that a model emitted imperfectly.
|
|
195
|
+
*
|
|
196
|
+
* Three failure modes show up in practice, in rising order of cost to recover:
|
|
197
|
+
*
|
|
198
|
+
* 1. Bad \u escapes - emoji written as \u{1F525} or a clipped \uD83.
|
|
199
|
+
* 2. Truncation - the response hit the upstream output-token ceiling mid-array,
|
|
200
|
+
* so the JSON simply stops. This is the one that used to surface as an opaque
|
|
201
|
+
* "JSON Parse error: Expected ']'", because the greedy \{[\s\S]*\} extraction
|
|
202
|
+
* ends at some inner object's closing brace.
|
|
203
|
+
* 3. Genuine malformation - a stray comma, an unescaped quote in a caption.
|
|
204
|
+
*
|
|
205
|
+
* (1) and (2) are recoverable here without a network round trip. Only (3) needs
|
|
206
|
+
* the model, so callers reach for AI repair (see ai/json-plan.ts) after this.
|
|
207
|
+
*/
|
|
208
|
+
/**
|
|
209
|
+
* Repair invalid \u escapes that JSON.parse rejects outright.
|
|
210
|
+
*
|
|
211
|
+
* Captions routinely contain emoji, and models emit them as the ES6 form
|
|
212
|
+
* \u{1F525} or as a truncated \uD83 rather than a bare character or a proper
|
|
213
|
+
* surrogate pair. Both are "Bad Unicode escape" to JSON.parse. Asking the model
|
|
214
|
+
* to fix its own output does not help here - it re-emits the same escape - so
|
|
215
|
+
* normalise deterministically before spending a round trip.
|
|
216
|
+
*/
|
|
217
|
+
declare function repairUnicodeEscapes(content: string): string;
|
|
218
|
+
/**
|
|
219
|
+
* Recover the longest valid prefix of a truncated JSON document.
|
|
220
|
+
*
|
|
221
|
+
* Walks the text once recording every position that sits immediately after a
|
|
222
|
+
* *complete* value, along with the bracket stack open at that point. Then works
|
|
223
|
+
* backwards from the end, cutting at each candidate and appending the closers
|
|
224
|
+
* that stack needs. The first prefix that parses wins, which for a truncated
|
|
225
|
+
* steps array means every whole step survives and only the half-written one is
|
|
226
|
+
* dropped.
|
|
227
|
+
*
|
|
228
|
+
* Returns null when nothing parses - a document too mangled to be truncation.
|
|
229
|
+
*/
|
|
230
|
+
declare function salvageTruncatedJson(content: string): string | null;
|
|
231
|
+
/**
|
|
232
|
+
* Pull the JSON payload out of a model response that may be fenced, prefixed
|
|
233
|
+
* with prose, or cut off before its closing bracket.
|
|
234
|
+
*
|
|
235
|
+
* Yields candidates rather than one string: the trim-to-last-closer variant is
|
|
236
|
+
* right when the model appended prose, and the run-to-end variant is right when
|
|
237
|
+
* the response was truncated (the last closer is then some inner object's).
|
|
238
|
+
*/
|
|
239
|
+
declare function extractJsonCandidates(content: string): string[];
|
|
240
|
+
interface LenientParse<T> {
|
|
241
|
+
value: T;
|
|
242
|
+
/** True when the text needed repair, i.e. worth telling the user about. */
|
|
243
|
+
repaired: boolean;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Parse JSON out of a model response, repairing what can be repaired without
|
|
247
|
+
* calling back out to the model. Returns null if nothing salvageable is there.
|
|
248
|
+
*/
|
|
249
|
+
declare function parseAIJson<T>(content: string): LenientParse<T> | null;
|
|
250
|
+
|
|
175
251
|
declare const CURSOR_CSS = "\n #qp-cursor {\n position: fixed;\n width: 32px;\n height: 38px;\n background: url(\"data:image/png;base64,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\") no-repeat;\n background-size: contain;\n pointer-events: none;\n z-index: 2147483647;\n transform: translate(-3px, -3px);\n transition: left 800ms ease-out, top 800ms ease-out, transform 0.08s ease-out;\n filter: drop-shadow(1px 1px 2px rgba(0,0,0,0.3));\n }\n #qp-cursor.clicking {\n transform: translate(-3px, -3px) scale(0.9);\n }\n";
|
|
176
252
|
/**
|
|
177
253
|
* JavaScript to inject for cursor tracking
|
|
@@ -303,4 +379,4 @@ declare function buildWatermarkFilters(opts: {
|
|
|
303
379
|
videoDuration: number;
|
|
304
380
|
}): string;
|
|
305
381
|
|
|
306
|
-
export { type ApplyTransitionsOptions, type AudioResult, type BlendTransition, CURSOR_CSS, CURSOR_PNG, CURSOR_SCRIPT, type ComposeOptions, type ConcatVideoOptions, Config, type SpeedUpOptions, type SpliceVideosOptions, type StepAudio, type StepSync, type StepTransition, type TTSStep, type TimeSegment, UserTier, type VideoOverlay, type VoiceoverMeta, type WordTiming, alignVoiceoverToRecording, applyTransitions, buildKeepSegments, buildStepTransitions, buildWatermarkFilters, canReuseVoiceover, composeVideo, concatMedia, concatVideoWithOutro, estimateWordTimings, generateASSHeader, generateSilence, generateVoiceover, getMediaDuration, getUpgradeUrl, loadExistingVoiceover, loadVoiceoverMeta, mapTimestampsAfterCompression, registerFreeUser, resolveVoice, shouldWatermark, speedUpVideo, spliceVideos, synthesizeSpeech };
|
|
382
|
+
export { type ApplyTransitionsOptions, type AudioResult, type BlendTransition, CURSOR_CSS, CURSOR_PNG, CURSOR_SCRIPT, type ComposeOptions, type ConcatVideoOptions, Config, type LenientParse, type SpeedUpOptions, type SpliceVideosOptions, type StepAudio, type StepSync, type StepTransition, type TTSStep, type TimeSegment, UserTier, type VideoOverlay, type VoiceoverMeta, type WordTiming, alignVoiceoverToRecording, applyTransitions, buildConcatArgs, buildKeepSegments, buildStepTransitions, buildWatermarkFilters, canReuseVoiceover, composeVideo, concatMedia, concatVideoWithOutro, estimateWordTimings, extractJsonCandidates, generateASSHeader, generateSilence, generateVoiceover, getAudioCodec, getMediaDuration, getUpgradeUrl, isHonestWav, loadExistingVoiceover, loadVoiceoverMeta, mapTimestampsAfterCompression, parseAIJson, registerFreeUser, repairUnicodeEscapes, resolveVoice, salvageTruncatedJson, shouldWatermark, speedUpVideo, spliceVideos, synthesizeSpeech };
|