- Python 33.3%
- JavaScript 31.1%
- CSS 26.3%
- HTML 8.1%
- Dockerfile 1.2%
- a personal access token makes the push trigger ci.yaml, so lint, build and deploy run there instead of being duplicated in scrape.yaml |
||
|---|---|---|
| .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 ics_export.pyto 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.py # 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. Pushes made with the automatic Actions token don't trigger ci.yaml, so the workflow builds and pushes the Docker image and calls the Portainer webhook itself when it committed new data — 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.