Minimalistic Wallpaper Collection 的 CI 秘籍:GitHub Actions 自动校验壁纸尺寸 + TinyPNG 压缩的完整实现
Minimalistic Wallpaper Collection 的 CI 秘籍:GitHub Actions 自动校验壁纸尺寸 + TinyPNG 压缩的完整实现
Minimalistic Wallpaper Collection 是一个收录 300+ 张极简风、扁平化艺术与自然主题的 4K 数字壁纸的开源合集,还附带一个可随机抽取壁纸的 API。这个项目最有意思的地方在于它的 CI 流水线:每次向仓库提交新壁纸时,GitHub Actions 会自动校验壁纸尺寸(宽高是否达标、比例是否失调),并调用 TinyPNG 对新增/修改的图片做体积优化,然后自动提交回仓库——整个过程无需人工干预,堪称图片类仓库的自动化样板。
项目结构速览:CI 都在哪里
整个仓库非常精简,所有 CI 相关的内容都集中在 .github/ 目录下:
| 文件 | 作用 |
|---|---|
| .github/workflows/check-wallpapers.yml | 壁纸尺寸校验工作流 |
| .github/workflows/tinify-images.yml | TinyPNG 图片优化工作流 |
| .github/workflows/vercel-deploy.yml | 自动部署网站到 Vercel |
| .github/scripts/check_wallpapers.py | 尺寸校验脚本本体 |
| .github/scripts/tinify_images.py | TinyPNG 压缩脚本本体 |
| api/index.php | 壁纸网站 + 随机壁纸 API 入口 |
壁纸本体全部放在 images/ 目录中,文件名约定为「作者-壁纸标题.扩展名」,例如 OGARart-eagle-mountain-sunset-minimalist.jpg。
壁纸尺寸校验:自动把关 4K 画质
校验规则是什么
check_wallpapers.py 基于 Pillow 读取每张图的真实像素,执行两条规则:
- 分辨率下限:宽至少 1920、高至少 1080,低于即判不合格(仓库期望值是 3840×2160);
- 宽高比上限:宽/高比值必须 ≥ 1.5,用来拦截竖图或接近正方形的图,保证壁纸适合横屏桌面。
只要发现不合格图片,脚本就会打印明细列表并以非零状态码退出,CI 随即红灯。
工作流是怎么触发的
check-wallpapers.yml 的触发配置体现了两个小技巧:
- 触发事件:
push(main 分支)、pull_request(指向 main)以及workflow_dispatch(允许在网页上手动重跑); - 路径过滤:
paths限定为**.jpg、**.jpeg、**.png、**.webp——只有图片文件变动才会跑,纯文档改动完全不打扰。
流水线步骤为:actions/checkout 拉代码 → setup-python 安装 Python 3.10 → pip install Pillow → 执行校验脚本。注意脚本结尾这段「保险丝」逻辑:
python .github/scripts/check_wallpapers.py -d images
if [ $? -ne 0 ]; then
exit 1
fi
脚本本身用 sys.exit("...") 报错(退出码恒为 1),这里显式再兜底一次 exit 1,确保任何异常都一定能让 CI 失败。
想在本地跑一遍?
只需要 Python 3.10+ 和 Pillow,即可离线复现 CI 的校验结果:
pip install Pillow
python .github/scripts/check_wallpapers.py -d images
参数还支持自定义门槛,比如 --min_width 2560 --max_ratio 1.6,方便其他图片仓库直接搬走这套脚本。
TinyPNG 压缩流水线:只压新图,自动回写
流程拆解:五步全自动
tinify-images.yml 是整套 CI 的精华,只在 pull_request 触发,步骤如下:
- 检出 PR 头分支:
checkout显式指定repository为 PR 头仓库、ref为 PR 头分支,这样即使来自 Fork 也能正确获取代码; - 找出变更文件:用 jitterbit/get-changed-files 动作输出本次 PR 新增/修改的文件清单(CSV 格式);
- 无图则跳过:清单为空时直接
exit 0,避免浪费 TinyPNG API 配额; - 执行压缩:tinify_images.py 通过
tinify官方库,把每个文件经tinify.from_buffer()压缩后原地覆盖,API 密钥从仓库 Secrets 的TINIFY_API_KEY注入(本地运行时也可用.env提供); - 自动提交:EndBug/add-and-commit 把压缩后的图片以
Optimize images with TinyPNG为提交信息追加到 PR 分支上。
为什么这套设计很聪明
- 只压增量:借助变更文件清单,历史壁纸不会被重复压缩(TinyPNG 是配额制 API,全量压缩 300 多张图既费配额又慢);
- PR 场景触发:压缩发生在 PR 分支而非 main,作者可以在合并前直接看到体积变化;
- 密钥不落库:
TINIFY_API_KEY存于 GitHub Secrets,命令行参数-k ${{ secrets.TINIFY_API_KEY }}在运行时注入。
脚本侧还做了类型过滤——只处理 png / jpg / jpeg 三种扩展名(见 tinify_images.py 中的 filter_files),配合 tqdm 显示进度条,本地手动跑体验也很友好:
pip install tinify tqdm python-dotenv
python .github/scripts/tinify_images.py -d images -ff images/xxx.jpg -k <你的API密钥>
顺带一提:部署也全自动
除了校验和压缩,vercel-deploy.yml 还负责把壁纸网站部署到 Vercel:推送到 main 时加 --prod 参数发布生产环境,PR 则生成预览部署。网站逻辑集中在 api/index.php,访问时可通过 ?random 参数随机返回一张壁纸,超过 4.5MB 的大图会自动改为重定向,vercel.json 则把所有路由都指向这个 PHP 入口。
总结:这套 CI 值得抄的三个模式
paths过滤 + 多事件触发:让检查只在该检查的时候运行,手动触发留好后手;- 增量处理:通过「获取变更文件」动作只对新增/修改的图做压缩,省配额也省时间;
- 自动回写:用
add-and-commit把优化结果追加到 PR,形成「提交即质检」的闭环。
对于任何以图片为主体的仓库(壁纸、素材库、教程配图),照搬 images/ + .github/ 这一套结构,就能立刻拥有一条尺寸校验 + 体积优化的自动化流水线。



