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
@@ -9,7 +9,7 @@ port; TLS, domain and proxy are out of scope.
|
||||
- [x] Phase 2: Recipes CRUD, visibility (private/public), photos, notes, search, favourites
|
||||
- [x] Phase 3: Comments, serving calculator (server-side `?portionen=`), cooking mode (wake lock)
|
||||
- [x] Phase 4: AI (OpenAI): "Mit KI aufbereiten" on the form + photo/screenshot and text import
|
||||
- [ ] Phase 5: Link import (schema.org JSON-LD, Instagram with paste fallback, Android PWA share target)
|
||||
- [x] Phase 5: Link import (schema.org JSON-LD, Instagram best effort + paste/screenshot fallback, PWA share target)
|
||||
- [ ] Phase 6: Backup script, full README
|
||||
|
||||
## Stack
|
||||
@@ -36,6 +36,13 @@ no JS build step: plain forms with small progressive enhancements in `static/js/
|
||||
re-validated by Pydantic (`AIRecipe`), `map_api_error` → German user messages, per-user/global daily
|
||||
limits (0 = off). `_create_completion` is the only network call (stubbed in tests). Drafts go into
|
||||
`RecipeForm(initial=…)` and are never saved directly. `import_views.py`: `/rezepte/import/` (photo, text).
|
||||
- `recipes/fetch.py` – the ONLY way to request user-supplied URLs: resolves once, requires public IPs,
|
||||
connects to the checked IP (no DNS rebinding), manual redirects re-checked, size/time limits, honest UA.
|
||||
`schema_org.py` parses JSON-LD Recipe + page text (stdlib HTMLParser). `instagram.py` makes one honest
|
||||
request to the post's embed page; Instagram mostly answers with an empty shell → UI falls back to
|
||||
paste/screenshot. Do not add UA spoofing, cookies or login-based scraping (owner's requirement).
|
||||
- `core/pwa.py` – manifest (share_target → `/teilen/`) and a no-cache service worker. Icons via
|
||||
`scripts/make_icons.py`.
|
||||
- `templates/`, `static/` – global templates, `app.css` (mobile first, dark mode), `app.js`.
|
||||
- `docker/entrypoint.sh` – migrate → ensure_admin → purge_ratelimits → gunicorn.
|
||||
- `scripts/` – `init-env.sh` (creates .env with secrets), `dev_server.py` (local run without Docker).
|
||||
|
||||
Reference in New Issue
Block a user