pix-cli 0.1.3__tar.gz → 0.1.4__tar.gz
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.
- {pix_cli-0.1.3 → pix_cli-0.1.4}/AGENTS.md +3 -2
- {pix_cli-0.1.3 → pix_cli-0.1.4}/PKG-INFO +42 -26
- {pix_cli-0.1.3 → pix_cli-0.1.4}/README.md +41 -25
- {pix_cli-0.1.3 → pix_cli-0.1.4}/README.zh-CN.md +41 -25
- {pix_cli-0.1.3 → pix_cli-0.1.4}/docs/architecture.md +60 -14
- {pix_cli-0.1.3 → pix_cli-0.1.4}/docs/decisions.md +22 -6
- {pix_cli-0.1.3 → pix_cli-0.1.4}/docs/development.md +4 -1
- {pix_cli-0.1.3 → pix_cli-0.1.4}/docs/roadmap.md +16 -6
- {pix_cli-0.1.3 → pix_cli-0.1.4}/pyproject.toml +1 -1
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/__init__.py +1 -1
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/config.py +19 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/default_config.toml +6 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/logger.py +3 -0
- pix_cli-0.1.4/src/pix/rclone.py +162 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/sync.py +109 -29
- {pix_cli-0.1.3 → pix_cli-0.1.4}/tests/test_cli.py +251 -20
- {pix_cli-0.1.3 → pix_cli-0.1.4}/uv.lock +1 -1
- pix_cli-0.1.3/src/pix/rclone.py +0 -72
- {pix_cli-0.1.3 → pix_cli-0.1.4}/.github/workflows/ci.yml +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/.github/workflows/publish.yml +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/.gitignore +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/.python-version +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/LICENSE +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/cli.py +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/doctor.py +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/py.typed +0 -0
- {pix_cli-0.1.3 → pix_cli-0.1.4}/src/pix/shrink.py +0 -0
|
@@ -32,9 +32,10 @@ uv build
|
|
|
32
32
|
- 不通过 shell 调用 `vips` 或 `rclone`。
|
|
33
33
|
- `-q` 是 quality,`--quiet` 是静默。
|
|
34
34
|
- 退出码 0/1/2,日志走 stderr;`mirror` / `publish` 透传 rclone 退出码。
|
|
35
|
-
- `mirror` / `publish` 使用 `rclone bisync
|
|
35
|
+
- `mirror` / `publish` 使用 `rclone bisync`;调用前先 `rclone mkdir` 目标并用 `rclone lsjson --max-depth 1` 判空。目标为空时自动加 `--resync`,目标非空时必须显式 `--resync`。用户不需要手动运行 rclone。它们是双向镜像,不是单向备份。
|
|
36
36
|
- `--max-delete` 默认 10(删除百分比,rclone bisync 语义);`mirror` / `publish` 源为空时默认拒绝,`--allow-empty` 加 `--resync` 才放行。
|
|
37
|
-
-
|
|
37
|
+
- `mirror` 默认只同步 `[mirror].include` 中的图片扩展名,`include = []` 关闭白名单;`publish` 固定只同步 `.avif`。两者用 rclone filters 文件(bisync `--filters-file`、判空 `--filter-from`)并加 `--ignore-case`。
|
|
38
|
+
- 修改 include/exclude 后必须提示用户先 `--resync`;升级到带过滤的版本后首次运行也需要 `--resync`。`--exclude` 是配置在前、命令行追加并去重。
|
|
38
39
|
- 增量状态固定在 `OUT/.pix/state.json`,每 200 个成功文件刷新并在 `finally` 落盘;`publish` 必须排除 `.pix/**`。
|
|
39
40
|
- `shrink` 必须拒绝目标冲突,`--prune` 必须拒绝空源,非 dry-run 必须持有 `OUT/.pix/lock`。
|
|
40
41
|
- `publish` 源必须至少有一个 `.avif`;`base_url` 必须以 `http://` 或 `https://` 开头。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pix-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Batch AVIF shrink and image-host sync CLI
|
|
5
5
|
Project-URL: Homepage, https://github.com/uzvg/pix
|
|
6
6
|
Project-URL: Repository, https://github.com/uzvg/pix
|
|
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
|
|
|
43
43
|
| `pix shrink` | Recursively compress images to AVIF, re-encoding only changed files |
|
|
44
44
|
| `pix mirror` | Bidirectionally mirror an original photo directory to a cloud drive |
|
|
45
45
|
| `pix publish` | Bidirectionally mirror AVIF output to an image host; optionally emit public URLs |
|
|
46
|
-
| `pix doctor` |
|
|
46
|
+
| `pix doctor` | Report Python, libvips and rclone versions, plus the config path |
|
|
47
47
|
| `pix config init` | Write a commented default configuration file |
|
|
48
48
|
|
|
49
49
|
`pix` is deliberately narrow:
|
|
@@ -66,7 +66,7 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
66
66
|
| `shrink` | pyvips thumbnail + AVIF encode | pix |
|
|
67
67
|
| `mirror` | `rclone bisync SRC REMOTE` | pix composes arguments, rclone executes |
|
|
68
68
|
| `publish` | `rclone bisync OUT REMOTE`, excluding `.pix/**` | pix + rclone |
|
|
69
|
-
| `doctor` / `config init` |
|
|
69
|
+
| `doctor` / `config init` | Runtime report / config scaffold | pix |
|
|
70
70
|
|
|
71
71
|
**Sync is rclone.** `mirror` and `publish` only compose `rclone bisync` arguments; rclone handles authentication, transfers and conflict handling. Configure remotes with `rclone config` before using them. `pix` never reads or writes `rclone.conf`.
|
|
72
72
|
|
|
@@ -76,14 +76,23 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
76
76
|
|
|
77
77
|
- Python 3.11+
|
|
78
78
|
- [uv](https://docs.astral.sh/uv/)
|
|
79
|
-
- rclone >= 1.66 for `mirror` / `publish`
|
|
79
|
+
- rclone >= 1.66 for `mirror` / `publish` (and for `pix doctor` to report a clean environment)
|
|
80
80
|
- At least one remote already configured in rclone
|
|
81
81
|
|
|
82
82
|
`pyvips[binary]` bundles libvips, so no separate vips installation is required.
|
|
83
83
|
|
|
84
84
|
## Install
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
Install from PyPI:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv tool install pix-cli
|
|
90
|
+
pix --version
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Upgrade with `uv tool upgrade pix-cli`; remove with `uv tool uninstall pix-cli`. Linux installs `~/.local/bin/pix`; Windows installs `%USERPROFILE%\.local\bin\pix.exe`.
|
|
94
|
+
|
|
95
|
+
To work on pix itself, install the checkout in editable mode:
|
|
87
96
|
|
|
88
97
|
```bash
|
|
89
98
|
git clone https://github.com/uzvg/pix.git
|
|
@@ -92,7 +101,7 @@ uv tool install --editable .
|
|
|
92
101
|
pix --version
|
|
93
102
|
```
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
An editable install picks up source changes immediately. Reinstall with `uv tool install --force --editable .`.
|
|
96
105
|
|
|
97
106
|
## Configure rclone
|
|
98
107
|
|
|
@@ -118,7 +127,7 @@ If the file is missing, built-in defaults are used. Generate a commented file wi
|
|
|
118
127
|
pix config init
|
|
119
128
|
```
|
|
120
129
|
|
|
121
|
-
Existing files are not overwritten; pass `--force` to replace one. Use `--config PATH` before the subcommand to point at another file.
|
|
130
|
+
Existing files are not overwritten; pass `--force` to replace one. Use `--config PATH` before the subcommand to point at another file; an explicit path must exist, while a missing default path is fine.
|
|
122
131
|
|
|
123
132
|
Common keys:
|
|
124
133
|
|
|
@@ -129,15 +138,18 @@ Common keys:
|
|
|
129
138
|
| | `effort` | `5` | libvips effort, 0–9 |
|
|
130
139
|
| | `min_size` | `0` | Skip sources smaller than this; accepts `500K`, `1M`, `2G` |
|
|
131
140
|
| | `include` | `jpg`, `jpeg`, `png`, `webp` | Extensions to scan, without dots |
|
|
132
|
-
| `[mirror]` | `
|
|
141
|
+
| `[mirror]` | `include` | common image extensions | Extensions to mirror, without dots; `[]` disables the whitelist |
|
|
142
|
+
| | `exclude` | `[]` | rclone exclude globs; command-line values are appended |
|
|
133
143
|
| | `max_delete` | `10` | Delete limit as a percentage; `-1` disables, `0` forbids |
|
|
134
144
|
| `[publish]` | `base_url` | `""` | Public URL prefix; must start with `http://` or `https://` |
|
|
135
145
|
| | `urls` | `false` | Emit a JSON URL manifest |
|
|
136
|
-
| | `exclude` | `[]` | Same as mirror |
|
|
146
|
+
| | `exclude` | `[]` | Same as mirror; `.pix/**` is always excluded first |
|
|
137
147
|
| | `max_delete` | `10` | Same as mirror |
|
|
138
148
|
| `[rclone]` | `binary` | `rclone` | rclone executable name or path |
|
|
139
149
|
|
|
140
|
-
Precedence is **command line > pix config > built-in defaults**. `--exclude` is appended to config excludes rather than replacing them. `-q` means quality;
|
|
150
|
+
Precedence is **command line > pix config > built-in defaults**. `--exclude` is appended to config excludes rather than replacing them. `-q` means quality; `--quiet` is errors-only; `-v` / `--verbose` adds per-file detail and rclone progress. `--no-urls` overrides `[publish].urls = true` for one run.
|
|
151
|
+
|
|
152
|
+
The default `[mirror].include` is `jpg`, `jpeg`, `png`, `webp`, `gif`, `bmp`, `tif`, `tiff`, `heic`, `heif`, `avif`, `jxl`, `svg`, `ico`, `cr2`, `cr3`, `nef`, `arw`, `dng`, `orf`, `raf`, `rw2`. Set it to `[]` to mirror every file.
|
|
141
153
|
|
|
142
154
|
## Quick start
|
|
143
155
|
|
|
@@ -154,16 +166,16 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
154
166
|
pix shrink -s ~/Pictures -d ~/Pictures-avif -w 1920 -q 85
|
|
155
167
|
```
|
|
156
168
|
|
|
157
|
-
The first run encodes everything; later runs skip unchanged files. State lives in `OUT/.pix/state.json`. Changing `width`, `quality` or `effort` triggers a full re-encode. `--dry-run` only prints the plan.
|
|
169
|
+
The first run encodes everything; later runs skip unchanged files. State lives in `OUT/.pix/state.json`. `-w` is a maximum long edge, so smaller images are not upscaled; relative directories are preserved under OUT. Change detection uses source size/mtime and output size, not content hashes. Changing `width`, `quality` or `effort` triggers a full re-encode. `--dry-run` only prints the plan. `--prune` removes only outputs recorded in state; extra files in OUT are left alone.
|
|
158
170
|
|
|
159
171
|
3. Mirror originals:
|
|
160
172
|
|
|
161
173
|
```bash
|
|
162
174
|
pix mirror -s ~/Pictures -d onedrive:photos --dry-run
|
|
163
|
-
pix mirror -s ~/Pictures -d onedrive:photos
|
|
175
|
+
pix mirror -s ~/Pictures -d onedrive:photos
|
|
164
176
|
```
|
|
165
177
|
|
|
166
|
-
`--resync` is
|
|
178
|
+
The destination is created automatically. Only files matching `[mirror].include` are mirrored; other source files are ignored, and non-matching files already on the destination are left untouched. If no source file matches the filter, the source counts as empty and is refused unless you pass `--allow-empty --resync`. An empty destination initializes its own baseline, so no `--resync` is needed on the first run. Use `--resync` to rebuild the baseline when the destination already has matching content, or after changing `include`/`exclude`; `--dry-run` may create an empty destination but does not transfer or delete. After upgrading from a version without include filtering, the first run also needs `--resync`; preview with `--dry-run --resync` first (the preview does not write the baseline).
|
|
167
179
|
|
|
168
180
|
4. Publish the AVIF output:
|
|
169
181
|
|
|
@@ -172,17 +184,18 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
172
184
|
--base-url https://img.example.com --urls > urls.json
|
|
173
185
|
```
|
|
174
186
|
|
|
175
|
-
`publish` requires at least one `.avif` in the source and always excludes `.pix/**`. The URL manifest is printed to stdout as JSON only after a successful, non-dry-run sync.
|
|
187
|
+
`publish` requires at least one `.avif` in the source unless you pass `--allow-empty --resync`; it syncs only `.avif` files and always excludes `.pix/**`. The URL manifest is printed to stdout as JSON only after a successful, non-dry-run sync. It lists every `.avif` under OUT, not just files changed in this run, and is not filtered by `[publish].exclude` or `--exclude`; excluded files can still appear in it. If you rely on excludes to hide files, do not publish the manifest until this behavior is fixed.
|
|
176
188
|
|
|
177
189
|
5. Re-run later:
|
|
178
190
|
|
|
179
191
|
```bash
|
|
180
192
|
pix shrink -s ~/Pictures -d ~/Pictures-avif
|
|
181
193
|
pix mirror -s ~/Pictures -d onedrive:photos
|
|
182
|
-
pix publish -s ~/Pictures-avif -d r2:images
|
|
194
|
+
pix publish -s ~/Pictures-avif -d r2:images \
|
|
195
|
+
--base-url https://img.example.com --urls
|
|
183
196
|
```
|
|
184
197
|
|
|
185
|
-
Only changes are encoded and transferred.
|
|
198
|
+
Only changes are encoded and transferred. `--base-url` is not persisted between runs; set `[publish].base_url` in config to avoid repeating it.
|
|
186
199
|
|
|
187
200
|
## Command cheat sheet
|
|
188
201
|
|
|
@@ -190,9 +203,10 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
190
203
|
|---|---|
|
|
191
204
|
| Preview compression | `pix shrink -s SRC -d OUT --dry-run` |
|
|
192
205
|
| Re-encode everything | `pix shrink -s SRC -d OUT --force` |
|
|
193
|
-
| Remove outputs whose source is gone | `pix shrink -s SRC -d OUT --prune` |
|
|
206
|
+
| Remove tracked outputs whose source is gone | `pix shrink -s SRC -d OUT --prune` |
|
|
194
207
|
| Preview a sync | `pix mirror -s SRC -d REMOTE --dry-run` |
|
|
195
|
-
| First
|
|
208
|
+
| First sync (new or empty destination) | `pix mirror -s SRC -d REMOTE` |
|
|
209
|
+
| Rebuild the baseline (non-empty destination, or after changing include/exclude) | `pix mirror -s SRC -d REMOTE --resync` |
|
|
196
210
|
| Emit a URL manifest | `pix publish -s OUT -d REMOTE --base-url https://img.example.com --urls` |
|
|
197
211
|
| Diagnose the environment | `pix doctor` |
|
|
198
212
|
| Generate a config file | `pix config init` |
|
|
@@ -202,19 +216,21 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
202
216
|
| Situation | What happens | Protection |
|
|
203
217
|
|---|---|---|
|
|
204
218
|
| Deletions on either side | Propagated in both directions; accidental deletion is irreversible | Preview with `--dry-run`; default `--max-delete 10` (percentage) |
|
|
205
|
-
| First sync |
|
|
206
|
-
|
|
|
207
|
-
|
|
|
219
|
+
| First sync (destination empty) | `pix` creates the destination and initializes the baseline | Preview with `--dry-run`; it may create an empty destination but does not transfer or delete. No manual rclone needed |
|
|
220
|
+
| Destination has matching content but no baseline | `pix` does not auto-resync; bisync fails instead of overwriting | Confirm which side is authoritative, then add `--resync` |
|
|
221
|
+
| Include/exclude filters changed | When filters are active, rclone detects the changed filters file and exits 7 | Run with `--resync` after changing `include` or `exclude`; `--dry-run --resync` previews but does not write the baseline |
|
|
222
|
+
| Non-image files in the source | `mirror` ignores them by default; `publish` ignores anything that is not `.avif`. If no file matches, the source counts as empty and is refused | Add extensions to `[mirror].include` if they should be mirrored; use `--allow-empty --resync` only for an intentional empty sync |
|
|
223
|
+
| Empty source | `mirror` / `publish` refuse. `shrink --prune` refuses only while state still has entries; empty state is a no-op | Use `--allow-empty` (plus `--resync` for sync) only when intentional |
|
|
208
224
|
| `a.jpg` and `a.jpeg` both exist | Both map to the same output | Detected before encoding; exits 2 |
|
|
209
225
|
| Two concurrent shrinks | They would write the same state and outputs | `OUT/.pix/lock` blocks the second process |
|
|
210
|
-
| State
|
|
226
|
+
| State missing or corrupt | Full rebuild; corrupt state logs a warning | Only causes re-encoding; outputs stay valid |
|
|
211
227
|
|
|
212
228
|
## Output and exit codes
|
|
213
229
|
|
|
214
230
|
- Logs and progress go to stderr.
|
|
215
|
-
- stdout carries `doctor` reports,
|
|
231
|
+
- stdout carries `doctor` reports, `shrink --dry-run` plans, `config init`'s `wrote <path>`, and `--urls` JSON. `mirror` / `publish --dry-run` output comes from rclone.
|
|
216
232
|
- Exit codes: `0` success, `1` runtime failure, `2` argument or configuration error.
|
|
217
|
-
- `mirror` / `publish` return rclone's exit code unchanged.
|
|
233
|
+
- `mirror` / `publish` return rclone's bisync exit code unchanged; destination preflight failures return 1.
|
|
218
234
|
|
|
219
235
|
URL manifest example:
|
|
220
236
|
|
|
@@ -230,9 +246,9 @@ URL manifest example:
|
|
|
230
246
|
|---|---|
|
|
231
247
|
| `pyvips/libvips unavailable` | Reinstall to bring libvips: `uv tool install --force --editable /path/to/pix`; or install libvips manually (Linux: `apt install libvips42`, Windows: libvips release zip on `PATH`) |
|
|
232
248
|
| rclone is older than 1.66 | Upgrade rclone |
|
|
233
|
-
| bisync reports a missing baseline |
|
|
249
|
+
| bisync reports a missing baseline or changed filters file | The destination has matching content, or the include/exclude rules changed (including the first run after upgrading). Confirm local should win, then add `--resync`; an empty destination initializes automatically. `--dry-run --resync` previews but does not write the baseline. |
|
|
234
250
|
| `OUT/.pix/lock` already exists | Check for another `shrink`, then remove a stale lock |
|
|
235
|
-
| Configuration fails to parse |
|
|
251
|
+
| Configuration fails to parse | The error names the file and location; fix the TOML or remove the file to fall back to defaults. `pix doctor` cannot run until the config parses |
|
|
236
252
|
| `publish` says the source has no `.avif` | Run `pix shrink` first |
|
|
237
253
|
| URL-related error | `base_url` must start with `http://` or `https://`, and `--urls` requires it |
|
|
238
254
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| `pix shrink` | Recursively compress images to AVIF, re-encoding only changed files |
|
|
16
16
|
| `pix mirror` | Bidirectionally mirror an original photo directory to a cloud drive |
|
|
17
17
|
| `pix publish` | Bidirectionally mirror AVIF output to an image host; optionally emit public URLs |
|
|
18
|
-
| `pix doctor` |
|
|
18
|
+
| `pix doctor` | Report Python, libvips and rclone versions, plus the config path |
|
|
19
19
|
| `pix config init` | Write a commented default configuration file |
|
|
20
20
|
|
|
21
21
|
`pix` is deliberately narrow:
|
|
@@ -38,7 +38,7 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
38
38
|
| `shrink` | pyvips thumbnail + AVIF encode | pix |
|
|
39
39
|
| `mirror` | `rclone bisync SRC REMOTE` | pix composes arguments, rclone executes |
|
|
40
40
|
| `publish` | `rclone bisync OUT REMOTE`, excluding `.pix/**` | pix + rclone |
|
|
41
|
-
| `doctor` / `config init` |
|
|
41
|
+
| `doctor` / `config init` | Runtime report / config scaffold | pix |
|
|
42
42
|
|
|
43
43
|
**Sync is rclone.** `mirror` and `publish` only compose `rclone bisync` arguments; rclone handles authentication, transfers and conflict handling. Configure remotes with `rclone config` before using them. `pix` never reads or writes `rclone.conf`.
|
|
44
44
|
|
|
@@ -48,14 +48,23 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
48
48
|
|
|
49
49
|
- Python 3.11+
|
|
50
50
|
- [uv](https://docs.astral.sh/uv/)
|
|
51
|
-
- rclone >= 1.66 for `mirror` / `publish`
|
|
51
|
+
- rclone >= 1.66 for `mirror` / `publish` (and for `pix doctor` to report a clean environment)
|
|
52
52
|
- At least one remote already configured in rclone
|
|
53
53
|
|
|
54
54
|
`pyvips[binary]` bundles libvips, so no separate vips installation is required.
|
|
55
55
|
|
|
56
56
|
## Install
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
Install from PyPI:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uv tool install pix-cli
|
|
62
|
+
pix --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Upgrade with `uv tool upgrade pix-cli`; remove with `uv tool uninstall pix-cli`. Linux installs `~/.local/bin/pix`; Windows installs `%USERPROFILE%\.local\bin\pix.exe`.
|
|
66
|
+
|
|
67
|
+
To work on pix itself, install the checkout in editable mode:
|
|
59
68
|
|
|
60
69
|
```bash
|
|
61
70
|
git clone https://github.com/uzvg/pix.git
|
|
@@ -64,7 +73,7 @@ uv tool install --editable .
|
|
|
64
73
|
pix --version
|
|
65
74
|
```
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
An editable install picks up source changes immediately. Reinstall with `uv tool install --force --editable .`.
|
|
68
77
|
|
|
69
78
|
## Configure rclone
|
|
70
79
|
|
|
@@ -90,7 +99,7 @@ If the file is missing, built-in defaults are used. Generate a commented file wi
|
|
|
90
99
|
pix config init
|
|
91
100
|
```
|
|
92
101
|
|
|
93
|
-
Existing files are not overwritten; pass `--force` to replace one. Use `--config PATH` before the subcommand to point at another file.
|
|
102
|
+
Existing files are not overwritten; pass `--force` to replace one. Use `--config PATH` before the subcommand to point at another file; an explicit path must exist, while a missing default path is fine.
|
|
94
103
|
|
|
95
104
|
Common keys:
|
|
96
105
|
|
|
@@ -101,15 +110,18 @@ Common keys:
|
|
|
101
110
|
| | `effort` | `5` | libvips effort, 0–9 |
|
|
102
111
|
| | `min_size` | `0` | Skip sources smaller than this; accepts `500K`, `1M`, `2G` |
|
|
103
112
|
| | `include` | `jpg`, `jpeg`, `png`, `webp` | Extensions to scan, without dots |
|
|
104
|
-
| `[mirror]` | `
|
|
113
|
+
| `[mirror]` | `include` | common image extensions | Extensions to mirror, without dots; `[]` disables the whitelist |
|
|
114
|
+
| | `exclude` | `[]` | rclone exclude globs; command-line values are appended |
|
|
105
115
|
| | `max_delete` | `10` | Delete limit as a percentage; `-1` disables, `0` forbids |
|
|
106
116
|
| `[publish]` | `base_url` | `""` | Public URL prefix; must start with `http://` or `https://` |
|
|
107
117
|
| | `urls` | `false` | Emit a JSON URL manifest |
|
|
108
|
-
| | `exclude` | `[]` | Same as mirror |
|
|
118
|
+
| | `exclude` | `[]` | Same as mirror; `.pix/**` is always excluded first |
|
|
109
119
|
| | `max_delete` | `10` | Same as mirror |
|
|
110
120
|
| `[rclone]` | `binary` | `rclone` | rclone executable name or path |
|
|
111
121
|
|
|
112
|
-
Precedence is **command line > pix config > built-in defaults**. `--exclude` is appended to config excludes rather than replacing them. `-q` means quality;
|
|
122
|
+
Precedence is **command line > pix config > built-in defaults**. `--exclude` is appended to config excludes rather than replacing them. `-q` means quality; `--quiet` is errors-only; `-v` / `--verbose` adds per-file detail and rclone progress. `--no-urls` overrides `[publish].urls = true` for one run.
|
|
123
|
+
|
|
124
|
+
The default `[mirror].include` is `jpg`, `jpeg`, `png`, `webp`, `gif`, `bmp`, `tif`, `tiff`, `heic`, `heif`, `avif`, `jxl`, `svg`, `ico`, `cr2`, `cr3`, `nef`, `arw`, `dng`, `orf`, `raf`, `rw2`. Set it to `[]` to mirror every file.
|
|
113
125
|
|
|
114
126
|
## Quick start
|
|
115
127
|
|
|
@@ -126,16 +138,16 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
126
138
|
pix shrink -s ~/Pictures -d ~/Pictures-avif -w 1920 -q 85
|
|
127
139
|
```
|
|
128
140
|
|
|
129
|
-
The first run encodes everything; later runs skip unchanged files. State lives in `OUT/.pix/state.json`. Changing `width`, `quality` or `effort` triggers a full re-encode. `--dry-run` only prints the plan.
|
|
141
|
+
The first run encodes everything; later runs skip unchanged files. State lives in `OUT/.pix/state.json`. `-w` is a maximum long edge, so smaller images are not upscaled; relative directories are preserved under OUT. Change detection uses source size/mtime and output size, not content hashes. Changing `width`, `quality` or `effort` triggers a full re-encode. `--dry-run` only prints the plan. `--prune` removes only outputs recorded in state; extra files in OUT are left alone.
|
|
130
142
|
|
|
131
143
|
3. Mirror originals:
|
|
132
144
|
|
|
133
145
|
```bash
|
|
134
146
|
pix mirror -s ~/Pictures -d onedrive:photos --dry-run
|
|
135
|
-
pix mirror -s ~/Pictures -d onedrive:photos
|
|
147
|
+
pix mirror -s ~/Pictures -d onedrive:photos
|
|
136
148
|
```
|
|
137
149
|
|
|
138
|
-
`--resync` is
|
|
150
|
+
The destination is created automatically. Only files matching `[mirror].include` are mirrored; other source files are ignored, and non-matching files already on the destination are left untouched. If no source file matches the filter, the source counts as empty and is refused unless you pass `--allow-empty --resync`. An empty destination initializes its own baseline, so no `--resync` is needed on the first run. Use `--resync` to rebuild the baseline when the destination already has matching content, or after changing `include`/`exclude`; `--dry-run` may create an empty destination but does not transfer or delete. After upgrading from a version without include filtering, the first run also needs `--resync`; preview with `--dry-run --resync` first (the preview does not write the baseline).
|
|
139
151
|
|
|
140
152
|
4. Publish the AVIF output:
|
|
141
153
|
|
|
@@ -144,17 +156,18 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
144
156
|
--base-url https://img.example.com --urls > urls.json
|
|
145
157
|
```
|
|
146
158
|
|
|
147
|
-
`publish` requires at least one `.avif` in the source and always excludes `.pix/**`. The URL manifest is printed to stdout as JSON only after a successful, non-dry-run sync.
|
|
159
|
+
`publish` requires at least one `.avif` in the source unless you pass `--allow-empty --resync`; it syncs only `.avif` files and always excludes `.pix/**`. The URL manifest is printed to stdout as JSON only after a successful, non-dry-run sync. It lists every `.avif` under OUT, not just files changed in this run, and is not filtered by `[publish].exclude` or `--exclude`; excluded files can still appear in it. If you rely on excludes to hide files, do not publish the manifest until this behavior is fixed.
|
|
148
160
|
|
|
149
161
|
5. Re-run later:
|
|
150
162
|
|
|
151
163
|
```bash
|
|
152
164
|
pix shrink -s ~/Pictures -d ~/Pictures-avif
|
|
153
165
|
pix mirror -s ~/Pictures -d onedrive:photos
|
|
154
|
-
pix publish -s ~/Pictures-avif -d r2:images
|
|
166
|
+
pix publish -s ~/Pictures-avif -d r2:images \
|
|
167
|
+
--base-url https://img.example.com --urls
|
|
155
168
|
```
|
|
156
169
|
|
|
157
|
-
Only changes are encoded and transferred.
|
|
170
|
+
Only changes are encoded and transferred. `--base-url` is not persisted between runs; set `[publish].base_url` in config to avoid repeating it.
|
|
158
171
|
|
|
159
172
|
## Command cheat sheet
|
|
160
173
|
|
|
@@ -162,9 +175,10 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
162
175
|
|---|---|
|
|
163
176
|
| Preview compression | `pix shrink -s SRC -d OUT --dry-run` |
|
|
164
177
|
| Re-encode everything | `pix shrink -s SRC -d OUT --force` |
|
|
165
|
-
| Remove outputs whose source is gone | `pix shrink -s SRC -d OUT --prune` |
|
|
178
|
+
| Remove tracked outputs whose source is gone | `pix shrink -s SRC -d OUT --prune` |
|
|
166
179
|
| Preview a sync | `pix mirror -s SRC -d REMOTE --dry-run` |
|
|
167
|
-
| First
|
|
180
|
+
| First sync (new or empty destination) | `pix mirror -s SRC -d REMOTE` |
|
|
181
|
+
| Rebuild the baseline (non-empty destination, or after changing include/exclude) | `pix mirror -s SRC -d REMOTE --resync` |
|
|
168
182
|
| Emit a URL manifest | `pix publish -s OUT -d REMOTE --base-url https://img.example.com --urls` |
|
|
169
183
|
| Diagnose the environment | `pix doctor` |
|
|
170
184
|
| Generate a config file | `pix config init` |
|
|
@@ -174,19 +188,21 @@ Precedence is **command line > pix config > built-in defaults**. `--exclude` is
|
|
|
174
188
|
| Situation | What happens | Protection |
|
|
175
189
|
|---|---|---|
|
|
176
190
|
| Deletions on either side | Propagated in both directions; accidental deletion is irreversible | Preview with `--dry-run`; default `--max-delete 10` (percentage) |
|
|
177
|
-
| First sync |
|
|
178
|
-
|
|
|
179
|
-
|
|
|
191
|
+
| First sync (destination empty) | `pix` creates the destination and initializes the baseline | Preview with `--dry-run`; it may create an empty destination but does not transfer or delete. No manual rclone needed |
|
|
192
|
+
| Destination has matching content but no baseline | `pix` does not auto-resync; bisync fails instead of overwriting | Confirm which side is authoritative, then add `--resync` |
|
|
193
|
+
| Include/exclude filters changed | When filters are active, rclone detects the changed filters file and exits 7 | Run with `--resync` after changing `include` or `exclude`; `--dry-run --resync` previews but does not write the baseline |
|
|
194
|
+
| Non-image files in the source | `mirror` ignores them by default; `publish` ignores anything that is not `.avif`. If no file matches, the source counts as empty and is refused | Add extensions to `[mirror].include` if they should be mirrored; use `--allow-empty --resync` only for an intentional empty sync |
|
|
195
|
+
| Empty source | `mirror` / `publish` refuse. `shrink --prune` refuses only while state still has entries; empty state is a no-op | Use `--allow-empty` (plus `--resync` for sync) only when intentional |
|
|
180
196
|
| `a.jpg` and `a.jpeg` both exist | Both map to the same output | Detected before encoding; exits 2 |
|
|
181
197
|
| Two concurrent shrinks | They would write the same state and outputs | `OUT/.pix/lock` blocks the second process |
|
|
182
|
-
| State
|
|
198
|
+
| State missing or corrupt | Full rebuild; corrupt state logs a warning | Only causes re-encoding; outputs stay valid |
|
|
183
199
|
|
|
184
200
|
## Output and exit codes
|
|
185
201
|
|
|
186
202
|
- Logs and progress go to stderr.
|
|
187
|
-
- stdout carries `doctor` reports,
|
|
203
|
+
- stdout carries `doctor` reports, `shrink --dry-run` plans, `config init`'s `wrote <path>`, and `--urls` JSON. `mirror` / `publish --dry-run` output comes from rclone.
|
|
188
204
|
- Exit codes: `0` success, `1` runtime failure, `2` argument or configuration error.
|
|
189
|
-
- `mirror` / `publish` return rclone's exit code unchanged.
|
|
205
|
+
- `mirror` / `publish` return rclone's bisync exit code unchanged; destination preflight failures return 1.
|
|
190
206
|
|
|
191
207
|
URL manifest example:
|
|
192
208
|
|
|
@@ -202,9 +218,9 @@ URL manifest example:
|
|
|
202
218
|
|---|---|
|
|
203
219
|
| `pyvips/libvips unavailable` | Reinstall to bring libvips: `uv tool install --force --editable /path/to/pix`; or install libvips manually (Linux: `apt install libvips42`, Windows: libvips release zip on `PATH`) |
|
|
204
220
|
| rclone is older than 1.66 | Upgrade rclone |
|
|
205
|
-
| bisync reports a missing baseline |
|
|
221
|
+
| bisync reports a missing baseline or changed filters file | The destination has matching content, or the include/exclude rules changed (including the first run after upgrading). Confirm local should win, then add `--resync`; an empty destination initializes automatically. `--dry-run --resync` previews but does not write the baseline. |
|
|
206
222
|
| `OUT/.pix/lock` already exists | Check for another `shrink`, then remove a stale lock |
|
|
207
|
-
| Configuration fails to parse |
|
|
223
|
+
| Configuration fails to parse | The error names the file and location; fix the TOML or remove the file to fall back to defaults. `pix doctor` cannot run until the config parses |
|
|
208
224
|
| `publish` says the source has no `.avif` | Run `pix shrink` first |
|
|
209
225
|
| URL-related error | `base_url` must start with `http://` or `https://`, and `--urls` requires it |
|
|
210
226
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| `pix shrink` | 递归压缩图片为 AVIF,只重新编码变化的文件 |
|
|
16
16
|
| `pix mirror` | 把原图目录与云盘做双向镜像 |
|
|
17
17
|
| `pix publish` | 把 AVIF 输出目录与图床做双向镜像,可选输出公开 URL |
|
|
18
|
-
| `pix doctor` |
|
|
18
|
+
| `pix doctor` | 报告 Python、libvips、rclone 版本与配置文件路径 |
|
|
19
19
|
| `pix config init` | 生成带注释的默认配置文件 |
|
|
20
20
|
|
|
21
21
|
`pix` 刻意保持边界清晰:
|
|
@@ -38,7 +38,7 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
38
38
|
| `shrink` | pyvips 缩放并编码 AVIF | pix |
|
|
39
39
|
| `mirror` | `rclone bisync SRC REMOTE` | pix 拼参数,rclone 执行 |
|
|
40
40
|
| `publish` | `rclone bisync OUT REMOTE`,排除 `.pix/**` | pix + rclone |
|
|
41
|
-
| `doctor` / `config init` |
|
|
41
|
+
| `doctor` / `config init` | 运行时报告 / 配置脚手架 | pix |
|
|
42
42
|
|
|
43
43
|
**同步由 rclone 执行。** `mirror` / `publish` 只负责拼装 `rclone bisync` 参数;认证、传输和冲突处理都由 rclone 完成。使用前请先用 `rclone config` 配好 remote。`pix` 不读取也不写入 `rclone.conf`。
|
|
44
44
|
|
|
@@ -48,14 +48,23 @@ photos/ ── mirror (rclone bisync) ──────────────
|
|
|
48
48
|
|
|
49
49
|
- Python 3.11+
|
|
50
50
|
- [uv](https://docs.astral.sh/uv/)
|
|
51
|
-
- `mirror` / `publish` 需要 rclone >= 1.66
|
|
51
|
+
- `mirror` / `publish` 需要 rclone >= 1.66;`pix doctor` 也要有 rclone 才会报告环境正常
|
|
52
52
|
- 已在 rclone 中配置好至少一个 remote
|
|
53
53
|
|
|
54
54
|
`pyvips[binary]` 自带 libvips,不需要单独安装 vips。
|
|
55
55
|
|
|
56
56
|
## 安装
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
从 PyPI 安装:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
uv tool install pix-cli
|
|
62
|
+
pix --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
升级用 `uv tool upgrade pix-cli`,卸载用 `uv tool uninstall pix-cli`。Linux 安装到 `~/.local/bin/pix`,Windows 为 `%USERPROFILE%\.local\bin\pix.exe`。
|
|
66
|
+
|
|
67
|
+
如果要开发 pix 本身,用 editable 模式安装源码:
|
|
59
68
|
|
|
60
69
|
```bash
|
|
61
70
|
git clone https://github.com/uzvg/pix.git
|
|
@@ -64,7 +73,7 @@ uv tool install --editable .
|
|
|
64
73
|
pix --version
|
|
65
74
|
```
|
|
66
75
|
|
|
67
|
-
|
|
76
|
+
editable 安装修改源码后立即生效。重装用 `uv tool install --force --editable .`。
|
|
68
77
|
|
|
69
78
|
## 配置 rclone
|
|
70
79
|
|
|
@@ -90,7 +99,7 @@ rclone 把凭据保存在 `~/.config/rclone/rclone.conf`(Windows:`%APPDATA%\
|
|
|
90
99
|
pix config init
|
|
91
100
|
```
|
|
92
101
|
|
|
93
|
-
已有文件不会被覆盖;需要替换时加 `--force`。用 `--config PATH
|
|
102
|
+
已有文件不会被覆盖;需要替换时加 `--force`。用 `--config PATH`(写在子命令之前)指向其他文件;显式路径必须存在,默认路径缺失则会使用内置默认值。
|
|
94
103
|
|
|
95
104
|
常用配置项:
|
|
96
105
|
|
|
@@ -101,15 +110,18 @@ pix config init
|
|
|
101
110
|
| | `effort` | `5` | libvips effort,0–9 |
|
|
102
111
|
| | `min_size` | `0` | 小于该值的源文件跳过;支持 `500K`、`1M`、`2G` |
|
|
103
112
|
| | `include` | `jpg`、`jpeg`、`png`、`webp` | 扫描扩展名,不带点 |
|
|
104
|
-
| `[mirror]` | `
|
|
113
|
+
| `[mirror]` | `include` | 常见图片扩展名 | 需要镜像的扩展名,不带点;`[]` 关闭白名单 |
|
|
114
|
+
| | `exclude` | `[]` | rclone 排除 glob;命令行项会追加 |
|
|
105
115
|
| | `max_delete` | `10` | 删除百分比上限;`-1` 不限制,`0` 禁止删除 |
|
|
106
116
|
| `[publish]` | `base_url` | `""` | 公开 URL 前缀,必须以 `http://` 或 `https://` 开头 |
|
|
107
117
|
| | `urls` | `false` | 是否输出 JSON URL 清单 |
|
|
108
|
-
| | `exclude` | `[]` | 同 `mirror
|
|
118
|
+
| | `exclude` | `[]` | 同 `mirror`;`.pix/**` 总是先被排除 |
|
|
109
119
|
| | `max_delete` | `10` | 同 `mirror` |
|
|
110
120
|
| `[rclone]` | `binary` | `rclone` | rclone 可执行文件名或路径 |
|
|
111
121
|
|
|
112
|
-
优先级为**命令行 > pix 配置 > 内置默认**。`--exclude` 是追加而非覆盖配置项。`-q` 表示 quality
|
|
122
|
+
优先级为**命令行 > pix 配置 > 内置默认**。`--exclude` 是追加而非覆盖配置项。`-q` 表示 quality;`--quiet` 只输出错误;`-v` / `--verbose` 输出每文件详情和 rclone 进度。`--no-urls` 可单次覆盖 `[publish].urls = true`。
|
|
123
|
+
|
|
124
|
+
`[mirror].include` 默认为 `jpg`、`jpeg`、`png`、`webp`、`gif`、`bmp`、`tif`、`tiff`、`heic`、`heif`、`avif`、`jxl`、`svg`、`ico`、`cr2`、`cr3`、`nef`、`arw`、`dng`、`orf`、`raf`、`rw2`。设为 `[]` 可镜像所有文件。
|
|
113
125
|
|
|
114
126
|
## 快速上手
|
|
115
127
|
|
|
@@ -126,16 +138,16 @@ pix config init
|
|
|
126
138
|
pix shrink -s ~/Pictures -d ~/Pictures-avif -w 1920 -q 85
|
|
127
139
|
```
|
|
128
140
|
|
|
129
|
-
首次全量编码,之后跳过未变化的文件。状态保存在 `OUT/.pix/state.json
|
|
141
|
+
首次全量编码,之后跳过未变化的文件。状态保存在 `OUT/.pix/state.json`。`-w` 是长边上限,小图不会被放大;输出会保留相对目录结构。变更检测基于源文件 size/mtime 和输出 size,不做内容哈希。修改 `width`、`quality` 或 `effort` 会触发全量重编码。`--dry-run` 只打印计划。`--prune` 只删除 state 中记录的输出,OUT 里的额外文件不会被清理。
|
|
130
142
|
|
|
131
143
|
3. 镜像原图:
|
|
132
144
|
|
|
133
145
|
```bash
|
|
134
146
|
pix mirror -s ~/Pictures -d onedrive:photos --dry-run
|
|
135
|
-
pix mirror -s ~/Pictures -d onedrive:photos
|
|
147
|
+
pix mirror -s ~/Pictures -d onedrive:photos
|
|
136
148
|
```
|
|
137
149
|
|
|
138
|
-
|
|
150
|
+
目标目录会自动创建。只有匹配 `[mirror].include` 的文件会被镜像;源目录里的其他文件会被忽略,目标上不匹配的文件也不会被删除。如果没有任何源文件匹配过滤规则,源会被视为空并拒绝同步,除非显式传入 `--allow-empty --resync`。目标为空时会自动初始化基线,首次运行不需要 `--resync`;目标已有匹配内容需要重建基线,或修改 `include` / `exclude` 后,才需要显式加 `--resync`。`--dry-run` 可能创建一个空目标目录,但不传输、不删除文件。从没有 include 过滤的旧版本升级后,首次运行也需要 `--resync`;建议先跑 `--dry-run --resync` 预览(预览不会写入基线)。
|
|
139
151
|
|
|
140
152
|
4. 发布 AVIF 输出:
|
|
141
153
|
|
|
@@ -144,17 +156,18 @@ pix config init
|
|
|
144
156
|
--base-url https://img.example.com --urls > urls.json
|
|
145
157
|
```
|
|
146
158
|
|
|
147
|
-
`publish` 要求源目录至少有一个 `.avif
|
|
159
|
+
`publish` 要求源目录至少有一个 `.avif`,除非显式传入 `--allow-empty --resync`;只同步 `.avif` 文件,并固定排除 `.pix/**`。URL 清单只在同步成功且不是 `--dry-run` 时输出到 stdout。清单列出 OUT 下所有 `.avif`,不只是本次变化的文件,也不按 `[publish].exclude` 或 `--exclude` 过滤;被排除的文件仍可能出现在清单里。如果依赖 exclude 隐藏文件,目前不要发布清单,直到该行为修复。
|
|
148
160
|
|
|
149
161
|
5. 之后重复运行:
|
|
150
162
|
|
|
151
163
|
```bash
|
|
152
164
|
pix shrink -s ~/Pictures -d ~/Pictures-avif
|
|
153
165
|
pix mirror -s ~/Pictures -d onedrive:photos
|
|
154
|
-
pix publish -s ~/Pictures-avif -d r2:images
|
|
166
|
+
pix publish -s ~/Pictures-avif -d r2:images \
|
|
167
|
+
--base-url https://img.example.com --urls
|
|
155
168
|
```
|
|
156
169
|
|
|
157
|
-
|
|
170
|
+
只处理变化的部分。`--base-url` 不会在两次运行之间保留;不想重复传就写进配置的 `[publish].base_url`。
|
|
158
171
|
|
|
159
172
|
## 常用命令
|
|
160
173
|
|
|
@@ -162,9 +175,10 @@ pix config init
|
|
|
162
175
|
|---|---|
|
|
163
176
|
| 预览压缩 | `pix shrink -s SRC -d OUT --dry-run` |
|
|
164
177
|
| 强制全部重压 | `pix shrink -s SRC -d OUT --force` |
|
|
165
|
-
|
|
|
178
|
+
| 删除 state 中记录、且源已消失的输出 | `pix shrink -s SRC -d OUT --prune` |
|
|
166
179
|
| 预览同步 | `pix mirror -s SRC -d REMOTE --dry-run` |
|
|
167
|
-
|
|
|
180
|
+
| 首次同步(目标不存在或为空) | `pix mirror -s SRC -d REMOTE` |
|
|
181
|
+
| 重建基线(目标非空,或修改 include/exclude 后) | `pix mirror -s SRC -d REMOTE --resync` |
|
|
168
182
|
| 输出 URL 清单 | `pix publish -s OUT -d REMOTE --base-url https://img.example.com --urls` |
|
|
169
183
|
| 诊断环境 | `pix doctor` |
|
|
170
184
|
| 生成配置文件 | `pix config init` |
|
|
@@ -174,19 +188,21 @@ pix config init
|
|
|
174
188
|
| 情况 | 会发生什么 | 如何防护 |
|
|
175
189
|
|---|---|---|
|
|
176
190
|
| 任意一侧删除文件 | 删除双向传播,误删不可逆 | 先 `--dry-run`;默认 `--max-delete 10`(百分比) |
|
|
177
|
-
|
|
|
178
|
-
|
|
|
179
|
-
|
|
|
191
|
+
| 首次同步(目标为空) | `pix` 自动创建目标并初始化基线 | 先 `--dry-run` 预览;它可能创建空目标目录,但不传输、不删除。不需要手动运行 rclone |
|
|
192
|
+
| 目标已有匹配内容但没有基线 | `pix` 不自动 resync,bisync 失败而不是覆盖 | 确认以哪边为准后显式加 `--resync` |
|
|
193
|
+
| 修改 include/exclude | 启用过滤时,rclone 会检测到 filters 文件变化并以 7 退出 | 修改后必须重新 `--resync`;`--dry-run --resync` 只预览,不写基线 |
|
|
194
|
+
| 源目录含非图片文件 | `mirror` 默认忽略;`publish` 只同步 `.avif`。如果没有任何文件匹配,源会被视为空并拒绝 | 需要镜像时把扩展名加入 `[mirror].include`;只有确认要空同步时才用 `--allow-empty --resync` |
|
|
195
|
+
| 源目录为空 | `mirror` / `publish` 默认拒绝;`shrink --prune` 仅在 state 仍有记录时拒绝,state 为空时是 no-op | 仅在确认要清空时用 `--allow-empty`(同步还需 `--resync`) |
|
|
180
196
|
| `a.jpg` 与 `a.jpeg` 同时存在 | 映射到同一输出 | 编码前检测并以 2 退出 |
|
|
181
197
|
| 同时运行两个 shrink | 会写同一份状态和输出 | `OUT/.pix/lock` 阻止第二个进程 |
|
|
182
|
-
|
|
|
198
|
+
| 状态文件缺失或损坏 | 全量重建;损坏时会告警 | 只会重新编码,不会产生错误结果 |
|
|
183
199
|
|
|
184
200
|
## 输出与退出码
|
|
185
201
|
|
|
186
202
|
- 日志和进度输出到 stderr。
|
|
187
|
-
- stdout 用于 `doctor`
|
|
203
|
+
- stdout 用于 `doctor` 报告、`shrink --dry-run` 计划、`config init` 的 `wrote <path>`,以及 `--urls` JSON;`mirror` / `publish --dry-run` 的输出由 rclone 产生。
|
|
188
204
|
- 退出码:`0` 成功,`1` 运行失败,`2` 参数或配置错误。
|
|
189
|
-
- `mirror` / `publish` 原样返回 rclone
|
|
205
|
+
- `mirror` / `publish` 原样返回 rclone bisync 的退出码;目标预检失败返回 1。
|
|
190
206
|
|
|
191
207
|
URL 清单示例:
|
|
192
208
|
|
|
@@ -202,9 +218,9 @@ URL 清单示例:
|
|
|
202
218
|
|---|---|
|
|
203
219
|
| 提示 `pyvips/libvips unavailable` | 重装以带入 libvips:`uv tool install --force --editable /path/to/pix`;或手动安装 libvips(Linux:`apt install libvips42`;Windows:下载 libvips release 压缩包并把 `bin` 加入 PATH) |
|
|
204
220
|
| rclone 版本低于 1.66 | 升级 rclone |
|
|
205
|
-
| bisync
|
|
221
|
+
| bisync 报缺少基线或 filters 文件变化 | 目标已有匹配内容,或 include/exclude 规则变化(含升级后首次运行)。确认本地为准后加 `--resync`;目标是空的会自动初始化。`--dry-run --resync` 只预览,不写基线 |
|
|
206
222
|
| `OUT/.pix/lock` 已存在 | 确认没有其他 `shrink` 在运行,再删除陈旧锁 |
|
|
207
|
-
| 配置解析失败 |
|
|
223
|
+
| 配置解析失败 | 错误信息会指出文件和位置;修复 TOML,或删除配置改用默认值。配置解析失败时 `pix doctor` 也会在加载配置阶段退出 2 |
|
|
208
224
|
| `publish` 提示源目录没有 `.avif` | 先运行 `pix shrink` |
|
|
209
225
|
| URL 相关报错 | `base_url` 必须以 `http://` 或 `https://` 开头,且 `--urls` 依赖它 |
|
|
210
226
|
|