Add phase 5: link import, Instagram fallback and share target
- 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]>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1bf8ef8b65
commit
60785e2437
@@ -0,0 +1,41 @@
|
||||
"""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()
|
||||
Reference in New Issue
Block a user