new-sakura:花枝朝向与分叉修正,素材包一键导出上传到对象存储
- gen_new_sakura.py:花朵加各自旋转角(原来一律朝上,像贴纸);分叉从垂直下垂改成向右上斜; 新增 --asset-base / --out —— 填前缀就引用对象存储位图,留空仍是内联 SVG。 - export_assets.py(新增):从 gen_new_sakura 的同一份 SVG 出图(直接 import,不另画一套), 用无头 Chrome 透明底渲染后转 WebP;--upload 一次传 CSS + 5 张 webp + 生成的 INSTALL.txt, 公开地址按 data/r2.txt 的 image_bucket_cdn_host(与 app.ini 同名)拼。 - serve.upload_files 支持逐文件 cacheControl。原来硬编码 immutable,而 INSTALL.txt 与镜像 CSS 的键不带版本 —— 重新生成后浏览器/CDN 一年内都还是旧内容。现在位图 1 天、CSS 5 分钟、 README 60 秒;selftest 补一条覆盖断言。 - 文档更正两处事实:①自定义域 r2.337845818.best 实测可匿名读(S3 endpoint 仍 403); ②服务端有 gzip,内联版 51KB 实际传输 3.9KB,比位图版(2.7KB + 5 图 48.9KB)小得多, 所以「换位图省 CSS 体积」不成立,位图只在素材要复用到非 CSS 场景时才有意义。 另记:曾以 immutable 传过的键必须去控制台清缓存,重传不会让边缘失效。
This commit is contained in:
@@ -1901,7 +1901,8 @@ function renderHostEditor(){
|
||||
tip.className = 'hint';
|
||||
tip.textContent = can === false
|
||||
? '当前是普通静态服务,没有上传接口。用 python dev/theme-builder/serve.py 启动生成器才能上传。'
|
||||
: '密钥只存在当前标签页(sessionStorage)与内存里,不进工程文件、不进导出 zip。'
|
||||
: '密钥只存在当前标签页(sessionStorage):刷新还在,关掉标签页就没了,也不进工程文件与导出 zip。'
|
||||
+ '想复用就别关标签页,或用脚本直传(见 dev/theme-tools/export_assets.py)。'
|
||||
+ '上传成功后会自动把「素材前缀」填成上面的图片地址。';
|
||||
el.appendChild(tip);
|
||||
|
||||
|
||||
@@ -63,6 +63,17 @@ def main():
|
||||
check("Content-Type = image/webp", ctype == "image/webp", str(ctype))
|
||||
check("Cache-Control = immutable", "immutable" in (cache or ""), str(cache))
|
||||
|
||||
# 2b) 逐文件覆盖缓存头:README/清单这类「键不变、内容会变」的文件不能 immutable
|
||||
serve.upload_files(cfg, [
|
||||
{"key": "shiroko/INSTALL.txt", "contentType": "text/plain; charset=utf-8",
|
||||
"cacheControl": "public, max-age=60",
|
||||
"data": base64.b64encode(b"readme").decode()},
|
||||
])
|
||||
_, _, cc = MockS3.store.get("themes/shiroko/INSTALL.txt", (b"", None, None))
|
||||
check("可覆盖 Cache-Control", cc == "public, max-age=60", str(cc))
|
||||
# 这一步只为验头,别让它污染后面的对象计数
|
||||
MockS3.store.pop("themes/shiroko/INSTALL.txt", None)
|
||||
|
||||
# 3) 错误密钥:HEAD 拿不到响应体(规范如此),只能按状态码归因;
|
||||
# 真正能读到 S3 错误码的是带 body 的 PUT,所以用上传路径验证还原能力。
|
||||
bad = serve.S3Config(dict(base, accessKey="BADKEY"))
|
||||
|
||||
@@ -326,8 +326,10 @@ def upload_files(cfg, files):
|
||||
raise ValueError("内容为空")
|
||||
ctype = str(f.get("contentType") or "application/octet-stream")
|
||||
# 素材键里带内容版本(导出时由 id 决定),内容不会原地变化 → immutable。
|
||||
status, _, body = s3_request(
|
||||
cfg, "PUT", key, data, ctype, "public, max-age=31536000, immutable")
|
||||
# 但清单/说明这类「键不变、内容会变」的文件不能 immutable,否则一年内看不到更新,
|
||||
# 所以允许逐个文件覆盖。
|
||||
cache = str(f.get("cacheControl") or "public, max-age=31536000, immutable")
|
||||
status, _, body = s3_request(cfg, "PUT", key, data, ctype, cache)
|
||||
if status >= 400:
|
||||
code, msg = _parse_s3_error(body)
|
||||
results.append({"key": key, "name": name, "ok": False,
|
||||
|
||||
Reference in New Issue
Block a user