chore: 完善开源项目文档与结构,移除敏感原始图片
- 重写 README.md,添加在线体验、API 文档、部署指南、技术栈等 - 添加 MIT LICENSE - 添加 CONTRIBUTING.md 贡献指南 - 添加 GitHub Issue/PR 模板 - 完善 .gitignore,防止原始图片和敏感文件误提交 - 从 git 中移除 25 个原始图片文件(.png/.jpg/非序号 webp) - 项目结构迁移:functions/ -> src/,根目录静态文件 -> public/ - 添加 wrangler.toml 与 package.json 配置
This commit is contained in:
103
build.py
103
build.py
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import venv
|
||||
@@ -11,11 +12,24 @@ from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
MANIFEST_PATH = BASE_DIR / "manifest.json"
|
||||
PUBLIC_DIR = BASE_DIR / "public"
|
||||
MANIFEST_PATH = PUBLIC_DIR / "manifest.json"
|
||||
|
||||
VARIANTS = {
|
||||
"mobile": [BASE_DIR / "mobile-image"],
|
||||
"desktop": [BASE_DIR / "desketop-image"],
|
||||
"mobile": {
|
||||
"out": PUBLIC_DIR / "mobile-image",
|
||||
"scan": [
|
||||
PUBLIC_DIR / "mobile-image",
|
||||
BASE_DIR / "mobile-image",
|
||||
],
|
||||
},
|
||||
"desktop": {
|
||||
"out": PUBLIC_DIR / "desketop-image",
|
||||
"scan": [
|
||||
PUBLIC_DIR / "desketop-image",
|
||||
BASE_DIR / "desketop-image",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
INPUT_EXTENSIONS = {
|
||||
@@ -81,14 +95,15 @@ def iter_source_files(directory: Path) -> list[Path]:
|
||||
return files
|
||||
|
||||
|
||||
def select_source_directory(candidates: list[Path]) -> Path:
|
||||
for directory in candidates:
|
||||
def select_scan_directory(scan_candidates: list[Path]) -> Path:
|
||||
"""优先有原图的目录,其次有序号 webp;否则退回 scan 第一项(通常为 public下的输出目录)。"""
|
||||
for directory in scan_candidates:
|
||||
if iter_source_files(directory):
|
||||
return directory
|
||||
for directory in candidates:
|
||||
if directory.exists():
|
||||
for directory in scan_candidates:
|
||||
if sorted_generated_webp_names(directory):
|
||||
return directory
|
||||
return candidates[0]
|
||||
return scan_candidates[0]
|
||||
|
||||
|
||||
def clear_generated_files(directory: Path) -> None:
|
||||
@@ -100,6 +115,23 @@ def clear_generated_files(directory: Path) -> None:
|
||||
path.unlink()
|
||||
|
||||
|
||||
def sorted_generated_webp_names(directory: Path) -> list[str]:
|
||||
"""已存在的序号 webp(无原图时再跑脚本不会清空)。"""
|
||||
if not directory.exists():
|
||||
return []
|
||||
names = [
|
||||
path.name
|
||||
for path in directory.iterdir()
|
||||
if path.is_file() and GENERATED_NAME_RE.match(path.name)
|
||||
]
|
||||
|
||||
def sort_key(entry: str) -> int:
|
||||
return int(Path(entry).stem)
|
||||
|
||||
names.sort(key=sort_key)
|
||||
return names
|
||||
|
||||
|
||||
def convert_to_webp(source: Path, target: Path, image_mod, image_ops) -> None:
|
||||
with image_mod.open(source) as image:
|
||||
image = image_ops.exif_transpose(image)
|
||||
@@ -114,24 +146,47 @@ def convert_to_webp(source: Path, target: Path, image_mod, image_ops) -> None:
|
||||
image.save(target, format="WEBP", quality=92, method=6)
|
||||
|
||||
|
||||
def build_variant(name: str, directories: list[Path], image_mod, image_ops) -> dict:
|
||||
directory = select_source_directory(directories)
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
clear_generated_files(directory)
|
||||
def copy_generated_webps(source_dir: Path, out_dir: Path, names: list[str]) -> None:
|
||||
"""将已有序号 webp 同步到 public 下的部署目录。"""
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
for entry in names:
|
||||
shutil.copy2(source_dir / entry, out_dir / entry)
|
||||
|
||||
|
||||
def build_variant(name: str, spec: dict[str, Path | list[Path]], image_mod, image_ops) -> dict:
|
||||
scan_dir = select_scan_directory(list(spec["scan"]))
|
||||
out_dir = spec["out"]
|
||||
out_dir.mkdir(parents=True, exist_ok=True)
|
||||
sources = iter_source_files(scan_dir)
|
||||
|
||||
sources = iter_source_files(directory)
|
||||
images: list[str] = []
|
||||
for index, source in enumerate(sources, start=1):
|
||||
target = directory / f"{index}.webp"
|
||||
try:
|
||||
convert_to_webp(source, target, image_mod, image_ops)
|
||||
images.append(target.name)
|
||||
print(f"[{name}] {source.name} -> {target.name}")
|
||||
except Exception as exc:
|
||||
print(f"[{name}] skip {source.name}: {exc}", file=sys.stderr)
|
||||
if sources:
|
||||
clear_generated_files(out_dir)
|
||||
for index, source in enumerate(sources, start=1):
|
||||
target = out_dir / f"{index}.webp"
|
||||
try:
|
||||
convert_to_webp(source, target, image_mod, image_ops)
|
||||
images.append(target.name)
|
||||
rel_src = os.path.relpath(source.resolve(), BASE_DIR.resolve())
|
||||
print(f"[{name}] {rel_src} -> {target.name}")
|
||||
except Exception as exc:
|
||||
print(f"[{name}] skip {source.name}: {exc}", file=sys.stderr)
|
||||
else:
|
||||
images = sorted_generated_webp_names(out_dir)
|
||||
if not images and scan_dir.resolve() != out_dir.resolve():
|
||||
legacy = sorted_generated_webp_names(scan_dir)
|
||||
if legacy:
|
||||
copy_generated_webps(scan_dir, out_dir, legacy)
|
||||
images = legacy
|
||||
print(f"[{name}] 已从 {scan_dir.relative_to(BASE_DIR)} 复制序号 webp ×{len(images)} -> public/")
|
||||
if images:
|
||||
if scan_dir.resolve() == out_dir.resolve():
|
||||
print(f"[{name}] 未检测到原图,保留 public 下序号 webp ×{len(images)}")
|
||||
else:
|
||||
print(f"[{name}] 跳过:未发现原图,且 public/ 与归档目录均无 1.webp 等序号文件")
|
||||
|
||||
return {
|
||||
"folder": directory.name,
|
||||
"folder": out_dir.name,
|
||||
"count": len(images),
|
||||
"images": images,
|
||||
}
|
||||
@@ -149,8 +204,8 @@ def main() -> int:
|
||||
"variants": {},
|
||||
}
|
||||
|
||||
for name, directories in VARIANTS.items():
|
||||
manifest["variants"][name] = build_variant(name, directories, image_mod, image_ops)
|
||||
for name, variant_spec in VARIANTS.items():
|
||||
manifest["variants"][name] = build_variant(name, variant_spec, image_mod, image_ops)
|
||||
|
||||
write_manifest(manifest)
|
||||
print(f"Wrote manifest: {MANIFEST_PATH}")
|
||||
|
||||
Reference in New Issue
Block a user