halfsize 0.1.4 → 0.1.5

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.5
4
+
5
+ - `--for discord` now targets 20 MB (Discord raised its free upload cap from 10 MB in August 2026)
6
+ - `--for wechat` now targets 20 MB (WeChat's chat-video cap, per its help center)
7
+ - The web app's presets and copy match the current caps
8
+ - `npx` installs behind a restrictive network can use the npmmirror FFmpeg mirror (see Install notes)
9
+
3
10
  ## 0.1.4
4
11
 
5
12
  - Batch mode: `halfsize a.mp4 b.mp4 --to 10mb` compresses several files in a row
package/README.md CHANGED
@@ -19,6 +19,7 @@
19
19
 
20
20
  <p align="center">
21
21
  <a href="README.zh-CN.md">中文说明</a> ·
22
+ <a href="https://YKLovePython.github.io/halfsize/">Website &amp; guides</a> ·
22
23
  <a href="#quick-start">Quick start</a> ·
23
24
  <a href="#how-it-works">How it works</a> ·
24
25
  <a href="#faq">FAQ</a>
@@ -26,7 +27,7 @@
26
27
 
27
28
  ---
28
29
 
29
- WeChat refuses anything over **25 MB**. Discord gives you **10 MB**. Email chokes around **20 MB**.
30
+ WeChat and Discord both stop at **20 MB**. Email chokes around the same.
30
31
  So you open a video editor, guess a bitrate, export, check the size, export again, and still
31
32
  can't tell whether the picture got worse.
32
33
 
@@ -40,7 +41,7 @@ It computes the bitrate, picks the resolution that actually fits, encodes twice,
40
41
  the result with **SSIM** and **VMAF** so you know whether it still looks the same.
41
42
 
42
43
  ```
43
- halfsize 0.1.4
44
+ halfsize 0.1.5
44
45
 
45
46
  source.mp4
46
47
  23.2 MB 8s 1920x1080 30.00 fps h264
@@ -51,9 +52,9 @@ the result with **SSIM** and **VMAF** so you know whether it still looks the sam
51
52
  estimate 1.94 MB (12x smaller)
52
53
  output source.2mb.mp4
53
54
 
54
- measuring quality done in 2s
55
+ measuring quality done in 1s
55
56
 
56
- 23.2 MB -> 1.99 MB 12x smaller 0.3% under target
57
+ 23.2 MB -> 1.99 MB 12x smaller 0.4% under target
57
58
  VMAF 84.4 SSIM 0.968 slight softening
58
59
 
59
60
  -> C:\Videos\source.2mb.mp4
@@ -61,7 +62,7 @@ the result with **SSIM** and **VMAF** so you know whether it still looks the sam
61
62
 
62
63
  ## Why this exists
63
64
 
64
- "Make it smaller" is a solved problem. **"Make it fit in exactly 25 MB, and tell me if it
65
+ "Make it smaller" is a solved problem. **"Make it fit in exactly 20 MB, and tell me if it
65
66
  still looks right"** is the part every tool makes you guess at.
66
67
 
67
68
  - HandBrake is excellent, but it asks you to think in codecs, RF values, and presets.
@@ -118,7 +119,7 @@ npm install -g halfsize
118
119
  npx halfsize --web
119
120
  ```
120
121
 
121
- Opens `http://127.0.0.1:4174` — drag a video in, pick 25 MB / 10 MB / 20 MB / 5 MB or type
122
+ Opens `http://127.0.0.1:4174` — drag a video in, pick 20 MB / 16 MB / 5 MB or type
122
123
  your own limit, and watch the encode. The file goes to a temporary folder **on your own
123
124
  machine**; nothing is sent anywhere.
124
125
 
@@ -129,6 +130,12 @@ machine**; nothing is sent anywhere.
129
130
  After each run you can download a **share card** (the image at the top of this README) with the
130
131
  real numbers on it.
131
132
 
133
+ Step-by-step guides with measured quality numbers:
134
+ [Discord 20 MB](https://YKLovePython.github.io/halfsize/discord/) ·
135
+ [WhatsApp 16 MB](https://YKLovePython.github.io/halfsize/whatsapp/) ·
136
+ [WeChat 20 MB](https://YKLovePython.github.io/halfsize/wechat/) ·
137
+ [any 20 MB limit](https://YKLovePython.github.io/halfsize/20mb/).
138
+
132
139
  ### Use it from an agent
133
140
 
134
141
  The repo ships a skill in [`skills/halfsize/SKILL.md`](skills/halfsize/SKILL.md). Drop that
@@ -162,6 +169,25 @@ below 70 clearly degraded
162
169
  VMAF is Netflix's perceptual metric; it correlates with human judgement far better than PSNR
163
170
  or bitrate. It is not magic, but it is a much better answer than "trust me".
164
171
 
172
+ ## What each size costs
173
+
174
+ Same 60-second 1080p clip, default settings, measured on a normal laptop:
175
+
176
+ | Target | Output | Resolution | Video bitrate | VMAF | Verdict |
177
+ |---|---|---|---|---|---|
178
+ | 20 MB | 19.45 MB | 1280×720 | 2.46 Mbps | 88.3 | slight softening |
179
+ | 16 MB | 15.59 MB | 960×540 | 1.94 Mbps | 84.8 | slight softening |
180
+ | 10 MB | 9.77 MB | 960×540 | 1.17 Mbps | 82.9 | slight softening |
181
+ | 5 MB | 4.93 MB | 640×360 | 0.55 Mbps | 72.0 | visible loss |
182
+
183
+ Source: 60 s, 1920×1080, 30 fps, 18 Mbps H.264 (136 MB). VMAF is measured against the
184
+ source at the midpoint, SSIM at three points. Real numbers move with content: a talking head
185
+ does much better than confetti.
186
+
187
+ At 20 MB the tool picked 720p on purpose. Sixty seconds of 1080p at 2.4 Mbps looks worse than
188
+ 720p at the same bits. `--no-downscale` overrides that, and `--codec h265` buys roughly 30%
189
+ more quality at the same size if your player supports it.
190
+
165
191
  ## CLI reference
166
192
 
167
193
  ```
@@ -187,19 +213,24 @@ halfsize <file> [options]
187
213
 
188
214
  Sizes accept `b`, `k`/`kb`, `m`/`mb`, `g`/`gb`, with or without a space. No unit means MB.
189
215
 
190
- `--for` uses the current free-tier caps: `discord` 10 MB, `whatsapp` 16 MB, `wechat` 25 MB,
191
- `email` 20 MB, `twitter` 512 MB. Caps change, so `--to` always overrides.
216
+ `--for` uses the current free-tier caps (checked November 2026): `discord` 20 MB,
217
+ `whatsapp` 16 MB, `wechat` 20 MB, `email` 20 MB, `twitter` 512 MB. Caps change, so `--to`
218
+ always overrides.
192
219
 
193
220
  Exit codes: `0` success, `1` error. `--json` returns the plan, the measured quality, and the
194
221
  target accuracy, which makes it easy to wrap in a script.
195
222
 
196
223
  ## Install notes
197
224
 
198
- `ffmpeg-static` and `ffprobe-static` download prebuilt binaries during `npm install`. If you are
199
- behind a proxy or a TLS-inspecting network, that download can fail. `halfsize` then falls back
200
- to any `ffmpeg` on your `PATH`, or to a build you point at explicitly:
225
+ `ffmpeg-static` downloads a prebuilt FFmpeg during `npm install`; FFprobe ships inside
226
+ `ffprobe-static`, so it needs no download. If you are behind a proxy or a TLS-inspecting
227
+ network, that download can fail. Point it at a mirror, or use a build you already have:
201
228
 
202
229
  ```bash
230
+ # use the npmmirror binary mirror (fast in mainland China)
231
+ FFMPEG_BINARIES_URL=https://registry.npmmirror.com/-/binary/ffmpeg-static npx halfsize video.mp4 --to 25mb
232
+
233
+ # or an FFmpeg already on disk
203
234
  HALFSIZE_FFMPEG=/path/to/ffmpeg HALFSIZE_FFPROBE=/path/to/ffprobe npx halfsize video.mp4 --to 25mb
204
235
  ```
205
236
 
@@ -212,14 +243,23 @@ Debian/Ubuntu, `sudo apt install ffmpeg`. Run `npx halfsize --doctor` to see wha
212
243
  No. The CLI never touches the network. The web app talks only to `127.0.0.1`, and uploaded
213
244
  files go to a temp directory that is deleted when the process exits.
214
245
 
246
+ **How do I get a video under Discord's 20 MB limit?**
247
+ `npx halfsize clip.mp4 --for discord` targets the free-tier cap (20 MB as of late 2026) and
248
+ writes a normal MP4 that plays in Discord's preview. Long 1080p clips usually come out at 720p;
249
+ that resolution drop is what buys the size.
250
+
251
+ **WeChat says the video is too large. What now?**
252
+ `npx halfsize clip.mp4 --for wechat` targets the 20 MB chat-video cap. If you need it smaller
253
+ still, pass `--to 10mb` (or any size) instead.
254
+
215
255
  **Why did it lower my resolution?**
216
- Because 25 MB of 4K is not enough bits to look good. Lowering resolution and keeping the
256
+ Because 20 MB of 4K is not enough bits to look good. Lowering resolution and keeping the
217
257
  bitrate per pixel sane almost always looks better than keeping 4K and starving it. Use
218
258
  `--no-downscale` if you want to override that.
219
259
 
220
260
  **Why is the output slightly under the target, not exactly on it?**
221
261
  Container overhead and two-pass ABR both vary a little. `halfsize` aims ~3% under so it never
222
- overshoots a hard platform cap. In the example above it landed 0.3% under.
262
+ overshoots a hard platform cap. In the example above it landed 0.4% under.
223
263
 
224
264
  **H.264 or H.265?**
225
265
  H.264 plays everywhere, including old Android phones and browsers. H.265 is roughly 30% smaller
package/README.zh-CN.md CHANGED
@@ -19,6 +19,7 @@
19
19
 
20
20
  <p align="center">
21
21
  <a href="README.md">English</a> ·
22
+ <a href="https://YKLovePython.github.io/halfsize/zh/">官网与教程</a> ·
22
23
  <a href="#快速开始">快速开始</a> ·
23
24
  <a href="#它怎么工作">它怎么工作</a> ·
24
25
  <a href="#常见问题">常见问题</a>
@@ -26,7 +27,7 @@
26
27
 
27
28
  ---
28
29
 
29
- 微信不让发超过 **25 MB**,Discord 只给 **10 MB**,邮件大多卡在 **20 MB**。
30
+ 微信和 Discord 都只让发 **20 MB**,邮件也大多卡在 **20 MB**。
30
31
  于是你打开剪辑软件,猜一个码率,导出,看一眼大小,再导一次——最后还是不知道画质到底掉了多少。
31
32
 
32
33
  `halfsize` 把这件事变成一行命令:
@@ -39,7 +40,7 @@ npx halfsize 婚礼.mp4 --to 25mb
39
40
  画质到底还在不在。
40
41
 
41
42
  ```
42
- halfsize 0.1.4
43
+ halfsize 0.1.5
43
44
 
44
45
  source.mp4
45
46
  23.2 MB 8s 1920x1080 30.00 fps h264
@@ -50,9 +51,9 @@ npx halfsize 婚礼.mp4 --to 25mb
50
51
  estimate 1.94 MB (12x smaller)
51
52
  output source.2mb.mp4
52
53
 
53
- measuring quality done in 2s
54
+ measuring quality done in 1s
54
55
 
55
- 23.2 MB -> 1.99 MB 12x smaller 0.3% under target
56
+ 23.2 MB -> 1.99 MB 12x smaller 0.4% under target
56
57
  VMAF 84.4 SSIM 0.968 slight softening
57
58
 
58
59
  -> C:\Videos\source.2mb.mp4
@@ -60,7 +61,7 @@ npx halfsize 婚礼.mp4 --to 25mb
60
61
 
61
62
  ## 为什么做这个
62
63
 
63
- 「把视频变小」早就有人解决了。真正没人做好的是:**「刚好塞进 25 MB,然后告诉我画质还行不行」**。
64
+ 「把视频变小」早就有人解决了。真正没人做好的是:**「刚好塞进 20 MB,然后告诉我画质还行不行」**。
64
65
 
65
66
  - HandBrake 很好用,但它要你想清楚编码器、RF 值、preset 这些词。
66
67
  - 在线压缩网站也能用,直到你想起自己刚把私人视频传给了陌生人。
@@ -115,7 +116,7 @@ npm install -g halfsize
115
116
  npx halfsize --web
116
117
  ```
117
118
 
118
- 打开 `http://127.0.0.1:4174`,把视频拖进去,选 25 MB / 10 MB / 20 MB / 5 MB,或者自己输入一个数,
119
+ 打开 `http://127.0.0.1:4174`,把视频拖进去,选 20 MB / 16 MB / 5 MB,或者自己输入一个数,
119
120
  然后看着它压。文件只会写进**你自己电脑**的临时目录,不会发到任何地方。
120
121
 
121
122
  <p align="center">
@@ -124,6 +125,12 @@ npx halfsize --web
124
125
 
125
126
  每次压完可以生成一张**分享图**(就是本文最上面那张),上面是这次真实的数字。
126
127
 
128
+ 附实测画质的分平台教程:
129
+ [微信 20 MB](https://YKLovePython.github.io/halfsize/zh/wechat/) ·
130
+ [任意 20 MB 限制](https://YKLovePython.github.io/halfsize/zh/20mb/) ·
131
+ [Discord 20 MB](https://YKLovePython.github.io/halfsize/discord/) ·
132
+ [WhatsApp 16 MB](https://YKLovePython.github.io/halfsize/whatsapp/)。
133
+
127
134
  ### 给 agent 用
128
135
 
129
136
  仓库里带了 [`skills/halfsize/SKILL.md`](skills/halfsize/SKILL.md)。把整个文件夹放进你的
@@ -152,6 +159,23 @@ VMAF ≥ 70 能看出损失
152
159
  VMAF 是 Netflix 提出的感知质量指标,比 PSNR 或「码率多少」更接近人眼判断。
153
160
  它不是魔法,但比「相信我」靠谱得多。
154
161
 
162
+ ## 各档大小到底损失多少画质
163
+
164
+ 同一个 60 秒 1080p 视频,默认设置,在普通笔记本上实测:
165
+
166
+ | 目标 | 输出 | 分辨率 | 视频码率 | VMAF | 结论 |
167
+ |---|---|---|---|---|---|
168
+ | 20 MB | 19.45 MB | 1280×720 | 2.46 Mbps | 88.3 | 轻微变软 |
169
+ | 16 MB | 15.59 MB | 960×540 | 1.94 Mbps | 84.8 | 轻微变软 |
170
+ | 10 MB | 9.77 MB | 960×540 | 1.17 Mbps | 82.9 | 轻微变软 |
171
+ | 5 MB | 4.93 MB | 640×360 | 0.55 Mbps | 72.0 | 能看出损失 |
172
+
173
+ 源片:60 秒、1920×1080、30fps、18 Mbps H.264(136 MB)。VMAF 在中间点对着源片测量,
174
+ SSIM 取三个采样点。实际数字会随内容变化:新闻口播会好很多,满屏彩纸会差很多。
175
+
176
+ 20 MB 这一档是故意降到 720p 的:60 秒 1080p 给 2.4 Mbps,还不如把同样的比特给 720p。
177
+ 想强制保分辨率就加 `--no-downscale`;播放器支持的话,`--codec h265` 能在同尺寸下多换约 30% 画质。
178
+
155
179
  ## 命令行参数
156
180
 
157
181
  ```
@@ -177,8 +201,8 @@ halfsize <file> [options]
177
201
 
178
202
  大小支持 `b`、`k`/`kb`、`m`/`mb`、`g`/`gb`,中间可以有空格。不写单位按 MB 算。
179
203
 
180
- `--for` 用的是当前免费档上限:`discord` 10 MB、`whatsapp` 16 MB、`wechat` 25 MB、
181
- `email` 20 MB、`twitter` 512 MB。平台上限会变,写死不如随时用 `--to` 覆盖。
204
+ `--for` 用的是当前免费档上限(2026 年 11 月核对):`discord` 20 MB、`whatsapp` 16 MB、
205
+ `wechat` 20 MB、`email` 20 MB、`twitter` 512 MB。平台上限会变,写死不如随时用 `--to` 覆盖。
182
206
 
183
207
  退出码:`0` 成功,`1` 出错。`--json` 会返回方案、画质测量和目标误差,方便包进脚本。
184
208
 
@@ -194,18 +218,39 @@ HALFSIZE_FFMPEG=/path/to/ffmpeg HALFSIZE_FFPROBE=/path/to/ffprobe npx halfsize v
194
218
  Windows 上 `winget install Gyan.FFmpeg` 就够了;macOS 用 `brew install ffmpeg`;
195
219
  Debian/Ubuntu 用 `sudo apt install ffmpeg`。跑一下 `npx halfsize --doctor` 能看到实际用的是哪个。
196
220
 
221
+ 如果 GitHub 下载慢或被阻断(大陆网络很常见),可以让 `ffmpeg-static` 改从 npmmirror 取二进制:
222
+
223
+ ```bash
224
+ # macOS / Linux
225
+ FFMPEG_BINARIES_URL=https://registry.npmmirror.com/-/binary/ffmpeg-static npx halfsize 视频.mp4 --to 25mb
226
+
227
+ # Windows PowerShell
228
+ $env:FFMPEG_BINARIES_URL="https://registry.npmmirror.com/-/binary/ffmpeg-static"; npx halfsize 视频.mp4 --to 25mb
229
+ ```
230
+
231
+ `ffprobe` 是随包附带的,不需要单独下载。已经装过系统 FFmpeg 的话,`halfsize` 会优先用它,
232
+ 连这一步都可以跳过。
233
+
197
234
  ## 常见问题
198
235
 
199
236
  **视频会被上传吗?**
200
237
  不会。命令行完全不联网。网页版只和 `127.0.0.1` 通信,上传的文件放在临时目录,进程退出就删掉。
201
238
 
239
+ **Discord 发不出去,怎么压到 20 MB?**
240
+ `npx halfsize 视频.mp4 --for discord` 会按免费档上限(2026 年底是 20 MB)压,输出就是普通 MP4,
241
+ Discord 预览能直接播。长一点的 1080p 视频通常会降到 720p,尺寸就是靠这一步省出来的。
242
+
243
+ **微信提示视频太大怎么办?**
244
+ `npx halfsize 视频.mp4 --for wechat` 会按微信聊天视频的 20 MB 上限压。还想更小就换成
245
+ `--to 10mb`(或者任意大小)。
246
+
202
247
  **为什么给我降分辨率了?**
203
- 因为 25 MB 的 4K 根本不够比特,硬撑 4K 只会满屏马赛克。降分辨率、把每像素比特数保住,
248
+ 因为 20 MB 的 4K 根本不够比特,硬撑 4K 只会满屏马赛克。降分辨率、把每像素比特数保住,
204
249
  通常比「分辨率不变但饿死编码器」好看得多。不想降就加 `--no-downscale`。
205
250
 
206
251
  **为什么输出比目标小一点,而不是刚好等于?**
207
252
  容器开销和两遍 ABR 都会有波动。`halfsize` 会刻意瞄准低 3%,保证不会超过平台的硬上限。
208
- 上面那个例子里,最终比目标低 0.3%。
253
+ 上面那个例子里,最终比目标低 0.4%。
209
254
 
210
255
  **H.264 还是 H.265?**
211
256
  H.264 到处都能播,包括老安卓机和浏览器。H.265 同画质大约小 30%,但部分剪辑软件和老硬件
package/package.json CHANGED
@@ -1,49 +1,59 @@
1
- {
2
- "name": "halfsize",
3
- "version": "0.1.4",
4
- "description": "Compress any video to an exact target size, locally, and prove the quality did not drop.",
5
- "type": "module",
6
- "bin": {
7
- "halfsize": "bin/halfsize.mjs"
8
- },
9
- "repository": {
10
- "type": "git",
11
- "url": "git+https://github.com/YKLovePython/halfsize.git"
12
- },
13
- "homepage": "https://github.com/YKLovePython/halfsize#readme",
14
- "bugs": {
15
- "url": "https://github.com/YKLovePython/halfsize/issues"
16
- },
17
- "engines": {
18
- "node": ">=18"
19
- },
20
- "files": [
21
- "bin",
22
- "src",
23
- "web",
24
- "README.md",
25
- "README.zh-CN.md",
26
- "CHANGELOG.md",
27
- "LICENSE"
28
- ],
29
- "scripts": {
30
- "start": "node bin/halfsize.mjs",
31
- "web": "node bin/halfsize.mjs --web",
32
- "test": "node --test test/human.test.mjs test/plan.test.mjs test/quality.test.mjs test/cli.test.mjs test/e2e.test.mjs"
33
- },
34
- "keywords": [
35
- "video",
36
- "compress",
37
- "video-compression",
38
- "ffmpeg",
39
- "target-size",
40
- "vmaf",
41
- "cli",
42
- "windows"
43
- ],
44
- "license": "MIT",
45
- "dependencies": {
46
- "ffmpeg-static": "^5.3.0",
47
- "ffprobe-static": "^3.1.0"
48
- }
49
- }
1
+ {
2
+ "name": "halfsize",
3
+ "version": "0.1.5",
4
+ "description": "Compress any video to an exact size (Discord or WeChat 20 MB, WhatsApp 16 MB) locally with FFmpeg and verify the quality with VMAF/SSIM.",
5
+ "type": "module",
6
+ "bin": {
7
+ "halfsize": "bin/halfsize.mjs"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/YKLovePython/halfsize.git"
12
+ },
13
+ "homepage": "https://YKLovePython.github.io/halfsize/",
14
+ "bugs": {
15
+ "url": "https://github.com/YKLovePython/halfsize/issues"
16
+ },
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "files": [
21
+ "bin",
22
+ "src",
23
+ "web",
24
+ "README.md",
25
+ "README.zh-CN.md",
26
+ "CHANGELOG.md",
27
+ "LICENSE"
28
+ ],
29
+ "scripts": {
30
+ "start": "node bin/halfsize.mjs",
31
+ "web": "node bin/halfsize.mjs --web",
32
+ "test": "node --test test/human.test.mjs test/plan.test.mjs test/quality.test.mjs test/cli.test.mjs test/e2e.test.mjs"
33
+ },
34
+ "keywords": [
35
+ "video",
36
+ "compress",
37
+ "compress-video",
38
+ "video-compression",
39
+ "video-compressor",
40
+ "reduce-video-size",
41
+ "ffmpeg",
42
+ "target-size",
43
+ "vmaf",
44
+ "ssim",
45
+ "discord",
46
+ "wechat",
47
+ "whatsapp",
48
+ "cli",
49
+ "privacy",
50
+ "windows",
51
+ "macos",
52
+ "linux"
53
+ ],
54
+ "license": "MIT",
55
+ "dependencies": {
56
+ "ffmpeg-static": "^5.3.0",
57
+ "ffprobe-static": "^3.1.0"
58
+ }
59
+ }
package/src/cli.mjs CHANGED
@@ -7,7 +7,7 @@ import { encode } from "./encode.mjs";
7
7
  import { measureQuality, verdict } from "./quality.mjs";
8
8
  import { bytes, duration, bitrate, ratio, parseSize, clock } from "./human.mjs";
9
9
 
10
- const VERSION = "0.1.4";
10
+ const VERSION = "0.1.5";
11
11
 
12
12
  const HELP = `
13
13
  halfsize ${VERSION} - compress a video to an exact size, and prove it still looks the same.
@@ -46,12 +46,13 @@ const HELP = `
46
46
 
47
47
  const DEFAULTS = { codec: "h264", preset: "medium", verify: true, downscale: true, audio: true };
48
48
 
49
- // Current upload caps as people hit them. Caps change, so --to always wins if a
50
- // preset is wrong for your account tier.
51
- const PLATFORMS = {
52
- discord: { bytes: 10 * 1_000_000, label: "Discord free (10 MB)" },
49
+ // Current upload caps as people hit them (checked November 2026). Discord raised
50
+ // its free cap to 20 MB in August 2026 and WeChat's chat-video cap is 20 MB.
51
+ // Caps change, so --to always wins if a preset is wrong for your account tier.
52
+ export const PLATFORMS = {
53
+ discord: { bytes: 20 * 1_000_000, label: "Discord free (20 MB)" },
53
54
  whatsapp: { bytes: 16 * 1_000_000, label: "WhatsApp media (16 MB)" },
54
- wechat: { bytes: 25 * 1_000_000, label: "WeChat video (25 MB)" },
55
+ wechat: { bytes: 20 * 1_000_000, label: "WeChat video (20 MB)" },
55
56
  email: { bytes: 20 * 1_000_000, label: "Email attachment (20 MB)" },
56
57
  twitter: { bytes: 512 * 1_000_000, label: "X / Twitter (512 MB)" },
57
58
  };
package/web/index.html CHANGED
@@ -138,6 +138,8 @@
138
138
  .error.on { display: block; }
139
139
 
140
140
  footer { margin-top: 46px; color: var(--dim); font-size: 12px; display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
141
+ footer a { color: var(--muted); }
142
+ footer a:hover { color: var(--accent); }
141
143
  .kbd { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--muted); background: var(--panel-2); border: 1px solid var(--line); padding: 3px 7px; border-radius: 6px; }
142
144
  .hidden { display: none !important; }
143
145
  </style>
@@ -150,7 +152,7 @@
150
152
  </header>
151
153
 
152
154
  <h1 data-i18n-html="title">把任何视频,塞进任何限制。<br><em>并且证明画质没变。</em></h1>
153
- <p class="sub" data-i18n-html="sub">微信只让发 25 MB,Discord 只让发 10 MB。选一个数字,剩下的交给它:算码率、降分辨率、两遍编码,最后用 <b>VMAF</b> 告诉你画质掉没掉。</p>
155
+ <p class="sub" data-i18n-html="sub">微信和 Discord 都只让发 20 MB,邮件也差不多。选一个数字,剩下的交给它:算码率、降分辨率、两遍编码,最后用 <b>VMAF</b> 告诉你画质掉没掉。</p>
154
156
 
155
157
  <div class="card" id="card">
156
158
  <div id="drop" class="drop" role="button" tabindex="0">
@@ -172,9 +174,8 @@
172
174
  <div>
173
175
  <div class="label" data-i18n="target">目标大小</div>
174
176
  <div class="chips" id="presets">
175
- <button class="chip on" data-size="25mb">25 MB<small data-i18n="wechat">微信</small></button>
176
- <button class="chip" data-size="10mb">10 MB<small>Discord</small></button>
177
- <button class="chip" data-size="20mb">20 MB<small data-i18n="email">邮件</small></button>
177
+ <button class="chip on" data-size="20mb">20 MB<small data-i18n="wechat">微信 / Discord</small></button>
178
+ <button class="chip" data-size="16mb">16 MB<small>WhatsApp</small></button>
178
179
  <button class="chip" data-size="5mb">5 MB<small data-i18n="web">网页</small></button>
179
180
  </div>
180
181
  <div class="row">
@@ -217,7 +218,7 @@
217
218
 
218
219
  <footer>
219
220
  <div><span class="kbd">npx halfsize video.mp4 --to 25mb</span></div>
220
- <div data-i18n="footer">本地 ffmpeg · 零上传 · MIT</div>
221
+ <div><span data-i18n="footer">本地 ffmpeg · 零上传 · MIT</span> · <a href="https://github.com/YKLovePython/halfsize" target="_blank" rel="noopener">GitHub ★</a> · <a href="https://YKLovePython.github.io/halfsize/" target="_blank" rel="noopener">Guides</a></div>
221
222
  </footer>
222
223
  </div>
223
224
 
@@ -226,7 +227,7 @@ const I18N = {
226
227
  zh: {
227
228
  pill: "本地运行 · 不上传 · 无账号",
228
229
  title: "把任何视频,塞进任何限制。<br><em>并且证明画质没变。</em>",
229
- sub: "微信只让发 25 MB,Discord 只让发 10 MB。选一个数字,剩下的交给它:算码率、降分辨率、两遍编码,最后用 <b>VMAF</b> 告诉你画质掉没掉。",
230
+ sub: "微信和 Discord 都只让发 20 MB,邮件也差不多。选一个数字,剩下的交给它:算码率、降分辨率、两遍编码,最后用 <b>VMAF</b> 告诉你画质掉没掉。",
230
231
  dropBig: "把视频拖进来,或点击选择",
231
232
  dropSmall: "MP4 · MOV · MKV · AVI · WebM · 不超过 8 GB",
232
233
  target: "目标大小",
@@ -242,8 +243,7 @@ const I18N = {
242
243
  verifying: "正在测画质…",
243
244
  done: "完成",
244
245
  uploading: "上传中",
245
- wechat: "微信",
246
- email: "邮件",
246
+ wechat: "微信 / Discord",
247
247
  web: "网页",
248
248
  smallerLabel: "更小",
249
249
  accuracyUnder: (p) => `比目标小 ${p}%`,
@@ -266,7 +266,7 @@ const I18N = {
266
266
  en: {
267
267
  pill: "runs locally · no upload · no account",
268
268
  title: "Fit any video into any limit.<br><em>And prove nothing changed.</em>",
269
- sub: "WeChat caps at 25 MB. Discord caps at 10 MB. Pick the number. It does the rest: bitrate math, resolution, two-pass encoding, then measures the result with <b>VMAF</b>.",
269
+ sub: "WeChat and Discord both cap videos at 20 MB. Email is about the same. Pick the number. It does the rest: bitrate math, resolution, two-pass encoding, then measures the result with <b>VMAF</b>.",
270
270
  dropBig: "Drop a video, or click to choose",
271
271
  dropSmall: "MP4 · MOV · MKV · AVI · WebM · up to 8 GB",
272
272
  target: "Target size",
@@ -282,8 +282,7 @@ const I18N = {
282
282
  verifying: "measuring quality…",
283
283
  done: "done",
284
284
  uploading: "uploading",
285
- wechat: "WeChat",
286
- email: "email",
285
+ wechat: "WeChat / Discord",
287
286
  web: "web",
288
287
  smallerLabel: "smaller",
289
288
  accuracyUnder: (p) => `${p}% under target`,
@@ -320,7 +319,7 @@ const drop = $("drop"), fileInput = $("file"), editor = $("editor"), preview = $
320
319
  const meta = $("meta"), fname = $("fname"), go = $("go"), progress = $("progress");
321
320
  const fill = $("fill"), pct = $("pct"), speed = $("speed"), result = $("result"), error = $("error");
322
321
 
323
- let state = { id: null, target: "25mb", codec: "h264", data: null };
322
+ let state = { id: null, target: "20mb", codec: "h264", data: null };
324
323
 
325
324
  function fmtBytes(n) {
326
325
  if (!n && n !== 0) return "—";