- SSRF-safe fetcher: public IPs only, connects to the checked address, redirects re-validated, size/time limits, honest user agent - schema.org/Recipe JSON-LD extraction (graphs, HowToSections, ISO durations, yields, keywords, images) without extra dependencies; AI fallback on plain page text when no structured recipe exists - Instagram: one login-free request to the public embed page; when Instagram withholds the caption, the import page explains how to paste the text or import a screenshot instead - Suggested source photo can be downloaded and attached on save - Text import works without AI (text becomes the description) - Installable PWA with manifest, icons and Android share target - Offline tests for SSRF rules, parsers, Instagram and import views Co-Authored-By: Claude Opus 5.5 <[email protected]>
42 lines
1.5 KiB
Python
42 lines
1.5 KiB
Python
"""Generates the PWA icons in static/icons (run once; output is committed)."""
|
|
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
OUT = Path(__file__).resolve().parent.parent / "static" / "icons"
|
|
ACCENT = (180, 83, 42)
|
|
CREAM = (250, 247, 242)
|
|
|
|
|
|
def draw_pot(size, padding):
|
|
img = Image.new("RGB", (size, size), ACCENT)
|
|
d = ImageDraw.Draw(img)
|
|
s = size - 2 * padding
|
|
x0, y0 = padding, padding
|
|
# pot body
|
|
d.rounded_rectangle([x0 + s * 0.18, y0 + s * 0.42, x0 + s * 0.82, y0 + s * 0.82], radius=s * 0.08, fill=CREAM)
|
|
# rim
|
|
d.rounded_rectangle([x0 + s * 0.12, y0 + s * 0.36, x0 + s * 0.88, y0 + s * 0.45], radius=s * 0.04, fill=CREAM)
|
|
# handles
|
|
d.rounded_rectangle([x0 + s * 0.05, y0 + s * 0.5, x0 + s * 0.2, y0 + s * 0.58], radius=s * 0.03, fill=CREAM)
|
|
d.rounded_rectangle([x0 + s * 0.8, y0 + s * 0.5, x0 + s * 0.95, y0 + s * 0.58], radius=s * 0.03, fill=CREAM)
|
|
# steam
|
|
for i, dx in enumerate((0.35, 0.5, 0.65)):
|
|
top = y0 + s * (0.12 if i == 1 else 0.17)
|
|
d.line([x0 + s * dx, top, x0 + s * dx, y0 + s * 0.3], fill=CREAM, width=max(2, int(s * 0.045)))
|
|
return img
|
|
|
|
|
|
def main():
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
draw_pot(192, 16).save(OUT / "icon-192.png")
|
|
draw_pot(512, 40).save(OUT / "icon-512.png")
|
|
draw_pot(512, 110).save(OUT / "icon-maskable-512.png") # content inside the safe zone
|
|
draw_pot(180, 14).save(OUT / "apple-touch-icon.png")
|
|
draw_pot(64, 4).save(OUT / "favicon.png")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|