Open-source project for Schniddzl.de, fetching and displaying restaurant menus automatically.
- Deployment
- Health Check
- How It Works
- Configuration
- Examples
- Dynamic Dates in Selectors
- Thumbnails
- Development
Deploy using Docker Compose. It pulls the latest image and exposes the app on the specified port.
Open the app locally: http://localhost:8156
services:
mittagskarte:
image: ghcr.io/flohoss/mittagskarte:latest
container_name: mittagskarte
restart: always
volumes:
- ./config:/app/config
deploy:
resources:
limits:
memory: 1G
cpus: '1.0'
reservations:
memory: 512M
cpus: '0.5'
ports:
- '8156:8156'GET /health or HEAD /health
Returns 200 OK with a simple response body (.) to indicate the application is running.
Mittagskarte fetches restaurant menus and converts them into fast-loading webp images.
Key features:
- Downloads menus in PDF or image formats
- Scrapes menus from HTML pages
- Converts menus to webp, reducing images wider than 1920px
- Updates menus automatically based on a cron schedule
See config/config.yaml for a full example.
| Key | Description |
|---|---|
api_token |
Required if a restaurant has no parse section. Used to upload a menu image manually. |
impressum |
Show legal info on the page (enabled: true) with responsible name and email. |
log_level |
Logging verbosity (debug, info, warn, error) |
meta.title |
Website title |
meta.description |
Suffix for the HTML description. Full HTML <meta> description = {meta.title} - {meta.description} |
meta.social |
Array of social media links (optional) |
restaurants |
Dictionary of restaurants |
server.address |
Host to bind (0.0.0.0 for all interfaces) |
server.port |
Port to serve the app |
time_zone |
Used for scheduling updates |
umami_analytics |
Optional analytics integration (enabled, domain, websiteid) |
Notes:
- Only
nameandurlare strictly required for each restaurant. - If
parseis empty,api_tokenmust be set. - Menus are automatically resized to a maximum width of 1920px.
Direct PDF download
parse:
update_cron: '30 9,10 * * 1,3'
direct_download: 'https://davvero-stuttgart.de/download/mittagskarte.pdf'
file_type: 'pdf'Image download via CSS selector
parse:
update_cron: '30 9,10 * * 1,2'
navigate:
- locator: '.et_pb_image_1 > span:nth-child(1) > img:nth-child(1)'
attribute: 'src'
file_type: 'image'HTML scraping
parse:
update_cron: '30 9,10 * * 1,4'
navigate:
- locator: 'p.paragraph-mittagstisch-right-corona'
style: '.w-nav { display: none !important; }'PDF link via XPath
parse:
update_cron: '30 9,10 1-3 * *'
navigate:
- locator: "//a[contains(text(), 'Mittagstisch')]"
file_type: 'pdf'All navigate steps use:
- locator: '<CSS or XPath selector>'
attribute: '<optional HTML attribute to fetch>'
style: '<optional CSS to hide unwanted elements>'Use {{date(...)}} to match menus dynamically.
| Argument | Description |
|---|---|
format |
Go time format (e.g., 02.01.2006, Jan) |
lang |
Language (en, de). Defaults to en |
day |
Weekday to adjust to (monday, tuesday, etc.) |
offset |
Number of weeks to shift (-1 last week, 0 this week, 1 next week) |
upper |
Convert output to uppercase |
Example:
'locator': "//div[@class='calendar']//span[text()='{{date(format=02.01.2006, day=fr, offset=-1)}}']"You can add custom thumbnails for restaurants to be displayed in the app.
-
Folder: Place your thumbnails inside the
config/thumbnailsdirectory. -
File Name: Name the thumbnail file exactly like the restaurant key in your
restaurantssection, with a.webpextension.-
Example: For the restaurant key
sw34, the thumbnail must be:config/thumbnails/sw34.webp
-
-
Format: Only WebP format is supported.
The app automatically uses the thumbnail for a restaurant:
background-image: url(/thumbnails/<restaurant_key>.webp);Example with sw34:
background-image: url(/thumbnails/sw34.webp);Note: WebP is required. You can convert images online using https://mazanoke.y8o.de/.
docker compose run --rm yarn install --frozen-lockfile
docker compose up --build --force-recreate- Auto-creates
config.yamlif missing
Go to http://localhost:7331 to view the app.
docker compose run --rm yarn upgrade --latestdocker compose run --rm go get -u && go mod tidydocker build --platform=linux/amd64 -f docker/dockerfile -t mittagskarte .