Files

69 lines
2.4 KiB
Python
Raw Permalink Normal View History

"""Turns a checkout of free-exercise-db into ZenXercise's bundled Exercise Library.
Writes `exercises.json` (slimmed, with each Exercise's Mode) and one WebP per
image into the output folder, flattened to `images/<id>_<n>.webp` because
Flutter assets are declared per folder.
"""
from __future__ import annotations
import json
from pathlib import Path
from PIL import Image
STRETCHING_CATEGORY = "stretching"
MAX_EDGE = 480
WEBP_QUALITY = 72
def mode_of(category: str) -> str:
"""Category `stretching` belongs to Stretching Mode, everything else to Workout Mode."""
return "stretching" if category == STRETCHING_CATEGORY else "workout"
def slim(exercise: dict) -> dict:
"""The fields the app needs, with images reduced to a count."""
return {
"id": exercise["id"],
"name": exercise["name"],
"mode": mode_of(exercise["category"]),
"category": exercise["category"],
"level": exercise["level"],
"equipment": exercise.get("equipment"),
"force": exercise.get("force"),
"mechanic": exercise.get("mechanic"),
"primaryMuscles": exercise["primaryMuscles"],
"secondaryMuscles": exercise["secondaryMuscles"],
"instructions": [line.strip() for line in exercise["instructions"] if line.strip()],
"imageCount": len(exercise["images"]),
}
def image_name(exercise_id: str, index: int) -> str:
return f"{exercise_id}_{index}.webp"
def convert_image(source: Path, target: Path) -> None:
with Image.open(source) as image:
image = image.convert("RGB")
image.thumbnail((MAX_EDGE, MAX_EDGE))
image.save(target, "WEBP", quality=WEBP_QUALITY, method=6)
def run(source_root: Path, output_root: Path) -> list[dict]:
exercises = json.loads((source_root / "dist" / "exercises.json").read_text(encoding="utf-8"))
images = output_root / "images"
images.mkdir(parents=True, exist_ok=True)
for stale in images.glob("*.webp"):
stale.unlink()
slimmed = sorted((slim(e) for e in exercises), key=lambda e: e["name"].lower())
for exercise in exercises:
for index, relative in enumerate(exercise["images"]):
convert_image(source_root / "exercises" / relative, images / image_name(exercise["id"], index))
(output_root / "exercises.json").write_text(
json.dumps(slimmed, ensure_ascii=False, separators=(",", ":")), encoding="utf-8"
)
return slimmed