- Python 34.8%
- JavaScript 28.1%
- CSS 27.4%
- HTML 8.5%
- Dockerfile 1.2%
DTSTAMP was derived from wall-clock time, so the whole file changed on every regeneration even with no new data -- the scheduled scrape workflow would have committed a no-op update every day. Derive it from each event's own date instead, so output is a pure function of fleamarkets.json. |
||
|---|---|---|
| .forgejo/workflows | ||
| .github | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| default.conf | ||
| docker-compose.yml | ||
| Dockerfile | ||
| fleamarkets.ics | ||
| fleamarkets.json | ||
| ics_export.py | ||
| index.html | ||
| pyproject.toml | ||
| README.md | ||
| scrape.py | ||
| script.js | ||
| style.css | ||
| uv.lock | ||
Flohmarkt-Kalender
A flea-market calendar for the Flensburg area, live at flohmarkt.freyd.is.
Architecture
Two independent parts:
- Scraper (
scrape.py) — fetches dates from flohmarkt-in-flensburg.de and marktcom.de and writes them tofleamarkets.json. Run manually or on a schedule. - Frontend (
index.html,style.css,script.js) — vanilla HTML/CSS/JS calendar that readsfleamarkets.jsonat runtime. Served by nginx via Docker. No build step, no framework. - iCalendar export (
ics_export.py) — convertsfleamarkets.jsonintofleamarkets.ics, an RFC 5545 feed served alongside the site so it can be subscribed to from calendar apps. Regenerated automatically at the end of everyscraperun; runuv run build-icsto regenerate it standalone (e.g. after a manual edit tofleamarkets.json).
fleamarkets.json is the contract between scraper and frontend: an array of { "date": "YYYY-MM-DD", "location": string } objects.
Subscribing on iPhone / Apple Calendar
The calendar is published as a live-updating subscription feed at https://flohmarkt.freyd.is/fleamarkets.ics.
- Tap the "📅 Im Kalender abonnieren" link on the site — Safari hands the
webcal://link straight to the Calendar app. - Or manually: Settings → Calendar → Accounts → Add Account → Other → Add Subscribed Calendar, and paste the URL above.
iOS refreshes subscribed calendars periodically (not instantly) — new/changed dates from fleamarkets.json show up automatically after the next scrape + refresh cycle.
Development
Requires Python 3.11+ and uv.
uv sync --group dev # install runtime + dev deps
pre-commit install # set up git hooks
uv run scrape # run the scraper
Deployment
The Docker image (nginx:alpine) is built and pushed in CI, then deployed via Portainer webhook.
docker compose up # run locally
Keeping dates up to date
A scheduled Forgejo Actions workflow (.forgejo/workflows/scrape.yaml) runs the scraper once a day, and commits + pushes fleamarkets.json/fleamarkets.ics if anything changed. That push triggers the normal CI pipeline (lint → Docker build/push → Portainer webhook deploy), so no manual steps are needed to keep the live calendar current. Trigger it manually anytime via the "Run workflow" button (workflow_dispatch) in the Actions tab.
Requires the repo's Actions token to have contents: write permission (checked under Settings → Actions in this Forgejo instance) — if the scheduled run fails to push, that's the first thing to check.