Only the classic watch URL was recognised, so a shorts link fell through
to the website extractor. That path fetches the page, finds no recipe
markup in what is a JavaScript shell, and hands the raw text to the
language model, which returns an empty recipe titled "null" — stored in
the history as an apparently successful extraction rather than an error.
Shorts are among the most common formats for recipe clips, so the
failure mode was both frequent and silent. Live URLs share the pattern.
On a host that has never run the service, the mounted data volume is
empty. Ownership was being corrected for a subdirectory that did not
exist yet, which aborted the entrypoint before the application started
— exactly the situation a fresh deployment creates, and the reason the
container came up on the existing Pi but would not have elsewhere.
Creating the directory has to happen at runtime rather than during the
build, because the volume mount hides whatever the image places there.
Setting the service up on a new host took 20 to 30 minutes, spent almost
entirely in the Debian ffmpeg dependency chain: several hundred packages
of X11 and desktop libraries that dpkg unpacks and configures file by
file onto an SD card. That cost is paid again on every fresh machine and
turned moving the service into a half-hour commitment rather than a
routine step.
Prebuilt binaries remove the package manager from the build entirely. A
cold build with nothing cached now finishes in about four minutes on Pi
hardware, verified end to end including audio transcoding.
Pinning the dependency versions is unrelated to build speed. It prevents
a rebuild months from now from silently resolving versions other than
those the running container was tested with.
data/ was added to .gitignore only after its contents had already been
committed, and an ignore rule never untracks existing files. The live
SQLite database therefore showed up as modified on every commit, made
accidental commits of user history likely, and bloated the repo with
binary churn.
Claude-Session: https://claude.ai/code/session_01QkiLqAtFamcbFXDnCtZSPm
Instagram and TikTok extraction silently breaks whenever yt-dlp falls
behind upstream API changes, and fixing it required a manual image
rebuild each time. Updating at container start ties the fix to the Pi's
weekly reboot instead, so the extractor stays current without operator
intervention. A failed update never blocks startup, because the network
may not be up yet right after boot.
.gitattributes pins LF for shell scripts: a CRLF checkout on Windows
would make the entrypoint unrunnable inside the Linux container.
Claude-Session: https://claude.ai/code/session_01QkiLqAtFamcbFXDnCtZSPm
- Bilder beim Extrahieren lokal cachen (data/images/{id}.ext) und über GET /api/history/{id}/image ausliefern; Löschen bei Verlaufseintrag-Entfernung
- history.db in ./data/ Volume verschoben, damit sie Container-Rebuilds überlebt
- yt-dlp Subprocess-Aufrufe auf Windows gefixt: run_in_executor statt asyncio.create_subprocess_exec (SelectorEventLoop-Kompatibilität)
- ./data:/app/data Docker-Volume für persistente Datenhaltung hinzugefügt