I created this site because of two reasons:
- I moved to Marseille and didn't find anything alike and
- I wanted to learn about vibecoding.
The later interest weighs more, so don't expect clean code or good style: close to everything here is autored by Claude Caude.
I don't intend to invest a lot of time in this project. I may go offline anytime, so don't rely on it. But if you feel like contributing, let's go!
Massalia Events is a static website that aggregates cultural events from multiple sources in Marseille. The site is built with Hugo and automatically updated through a local crawler that fetches events from configured sources.
Key Features:
- Aggregates events from multiple cultural venues and platforms
- Automatic categorization (danse, musique, theatre, art, communaute)
- Location-based filtering (Marseille area)
- Multi-day event support
- Automatic event expiration (past events hidden from public view)
- Optimized images in WebP format
- French language support
massalia.events/
├── content/
│ ├── events/ # Event markdown files (generated by crawler)
│ │ └── 2026/01/27/ # Date-based folder structure
│ └── locations/ # Venue pages (generated by script)
├── crawler/ # Python crawler application
│ ├── crawl.py # Main CLI entry point
│ ├── config.yaml # Main configuration
│ ├── config/ # Source and criteria configuration
│ ├── data/
│ │ └── venues.yaml # Venue data for location pages
│ └── src/ # Crawler source code
├── docs/ # Documentation
│ ├── WORKFLOW.md # Publishing workflow guide
│ └── TROUBLESHOOTING.md # Common issues and solutions
├── layouts/ # Hugo templates
├── scripts/
│ ├── generate-venue-pages.py # Generate location pages
│ ├── build.sh # Production build
│ ├── serve.sh # Development server
│ ├── clean.sh # Clean build artifacts
│ ├── check-deps.sh # Verify dependencies
│ └── maintenance/ # Maintenance utility scripts
├── assets/
│ └── images/events/ # Event images (generated by crawler)
├── specifications/ # Product specifications
├── Makefile # Convenient make targets
└── hugo.toml # Hugo configuration
Install these tools before setting up the project:
| Tool | Min Version | Install (macOS) | Purpose |
|---|---|---|---|
| Git | any | brew install git |
Version control |
| Python | 3.11+ | brew install python |
Crawler runtime |
| Hugo | 0.154+ (extended) | brew install hugo |
Static site generator |
| Go | 1.21+ (optional) | brew install go |
Hugo modules |
Verify with:
git --version
python3 --version # Must be 3.11 or higher
hugo version # Must show "extended"# 1. Install system dependencies (macOS with Homebrew)
brew install git python hugo
# 2. Clone repository (--recurse-submodules pulls the Blowfish theme)
git clone --recurse-submodules https://github.com/jstuker/massalia.events.git
cd massalia.events
# If you already cloned without --recurse-submodules, init the theme manually:
git submodule update --init --recursive
# 3. Set up crawler Python environment
cd crawler
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# 4. For Shotgun and AgendaCulturel parsers (browser automation)
pip install playwright && playwright install chromium
# 5. Verify everything works
make check # Check Hugo + Git + theme
cd crawler && python crawl.py validate # Check crawler config# 1. Activate crawler
cd crawler && source venv/bin/activate
# 2. Run crawler (preview first)
python crawl.py run --dry-run # Preview
python crawl.py run # Execute
# 3. Generate venue pages for new locations
python ../scripts/generate-venue-pages.py --dry-run
python ../scripts/generate-venue-pages.py
# 4. Preview site
cd .. && hugo server # Visit http://localhost:1313
# 5. Publish
git add -A
git commit -m "Add events from $(date +%Y-%m-%d) crawl"
git push origin main| Document | Description |
|---|---|
| Publishing Workflow | Step-by-step guide for daily operations |
| Troubleshooting | Common issues and solutions |
| Crawler Documentation | Detailed crawler usage and configuration |
| Product Specification | Project requirements and design |
See the Publishing Workflow for detailed instructions.
Quick checklist:
git pull origin maincd crawler && source venv/bin/activatepython crawl.py run --dry-run(preview)python crawl.py run(execute)python ../scripts/generate-venue-pages.py(create location pages for new venues)cd .. && git add -A && git commit -m "Add events"git push origin main
| Category | French Label | Description |
|---|---|---|
| danse | Danse | Dance performances and shows |
| musique | Musique | Concerts and music events |
| theatre | Théâtre | Theatre and performing arts |
| art | Art | Exhibitions and visual arts |
| communaute | Communauté | Community events and workshops |
Events reference venues by slug (e.g., la-friche, klap). Each venue needs a location page for the site to display venue information and link events properly.
After crawling, run the venue page generator to create pages for any new venues:
# Preview what would be created
python scripts/generate-venue-pages.py --dry-run
# Generate pages (skips existing)
python scripts/generate-venue-pages.pyThe script:
- Scans event files for location slugs
- Finds new slugs missing from
crawler/data/venues.yaml - Appends stub entries for discovered venues
- Creates
content/locations/[slug]/_index.fr.mdpages
New venues are added as stubs. Edit crawler/data/venues.yaml to fill in:
title- Display namedescription- 1-2 sentence French descriptionaddress- Street addresswebsite- Venue website URLtype- Venue type (Club, Theatre, etc.)body- Longer description for the page
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests:
cd crawler && pytest - Submit a pull request
See Crawler README for adding new event sources.
The project includes shell scripts and a Makefile for local development:
make help # Show all available targets
make serve # Start development server
make build # Production build
make clean # Remove build artifacts
make check # Verify dependencies
make crawl # Run event crawler
make test # Run tests./scripts/serve.sh # Start dev server at localhost:1313
./scripts/serve.sh --network # Allow network access
./scripts/build.sh # Build for production
./scripts/build.sh --drafts # Include draft content
./scripts/clean.sh # Clean build artifacts
./scripts/check-deps.sh # Check dependencies| Script | Option | Description |
|---|---|---|
| serve.sh | --no-drafts |
Exclude draft content |
| serve.sh | --network |
Bind to 0.0.0.0 |
| serve.sh | --port N |
Use custom port |
| build.sh | --drafts |
Include drafts |
| build.sh | --baseURL URL |
Override base URL |
| clean.sh | --all |
Also clean node_modules |
The project includes maintenance scripts for ongoing site health:
make maintenance # Run all maintenance checks
make update-theme # Update Blowfish theme to latest
make validate-config # Validate Hugo configuration
make validate-content # Check event front matter
make check-links # Check for broken links
make expire-events # List expired events
make cleanup # Remove stale artifacts| Script | Description |
|---|---|
update-theme.sh |
Check and update Blowfish theme submodule |
validate-config.sh |
Validate Hugo TOML configuration files |
check-links.sh |
Find broken internal/external links |
validate-content.sh |
Validate event markdown front matter |
cleanup.sh |
Remove temporary files and artifacts |
expire-events.sh |
Mark or delete past events |
| Script | Option | Description |
|---|---|---|
| update-theme.sh | --update |
Update theme to latest version |
| update-theme.sh | --version |
Show current version only |
| check-links.sh | --external |
Also check external links |
| check-links.sh | --images |
Verify image files exist |
| validate-content.sh | --verbose |
Show all files checked |
| cleanup.sh | --all |
Also clean orphaned images |
| cleanup.sh | --dry-run |
Preview without deleting |
| expire-events.sh | --mark |
Add expired: true to past events |
| expire-events.sh | --delete |
Remove past events and images |
| expire-events.sh | --days N |
Events older than N days |
Past events are automatically hidden from the public website while remaining in the content repository for historical reference.
- Expiration Flag: Each event has an
expired: falsefield in its front matter - Timezone: Events expire at midnight Europe/Paris time after the event date
- Display: Expired events are filtered from all listings (home, categories, tags, search)
- Direct Access: Accessing an expired event URL shows a friendly "Cet événement est passé" message
- Preservation: Expired event files remain in
/content/events/for Git history
# List past events
make expire-events
# Mark past events as expired
make mark-expired
# Or use the script directly
./scripts/maintenance/expire-events.sh --mark
# Delete events older than 30 days
./scripts/maintenance/expire-events.sh --delete --days 30New events created by the crawler include:
expired: false
expiryDate: 2026-01-28T00:00:00+01:00 # Hugo's built-in expiry- Static Site Generator: Hugo 0.154.4+ (extended)
- Theme: Blowfish
- Crawler: Python 3.11+
- Hosting: GitHub Pages
- CI/CD: GitHub Actions
Part of the Massalia Events project.
0 comments
log in to comment.