# Pixelfed Import & Demo Reorganisation — Design Spec **Date:** 2026-06-20 **Status:** Approved ## Overview Import 36 Pixelfed posts from `gram.social/m038` (exported as `pixelfed-statuses.json`) into three new permanent trips. Simultaneously reorganise the demo system: move the Italy demo trip to a clearly-labelled 2026 demo slug and retire the Japan demo entries. --- ## Scope ### What this covers 1. Demo system reorganisation (Italy 2025 demo → `italy-2026-demo`, Japan demo retired) 2. Three new real trip page trees 3. A one-time Python import script that routes posts to the correct trip, downloads photos, and writes Grav entry folders 4. Updated Makefile `demo-load` / `demo-reset` targets ### What this does not cover - Generating proper titles (done interactively with Claude after import) - Adding GPX routes to real trips - Lat/lng geocoding (location data from the export has city/country only, no coordinates) --- ## Part 1: Demo System Reorganisation ### 1a. Italy demo moves to `italy-2026-demo` Copy `user/docs/demo/trips/italy-2025/` → `user/docs/demo/trips/italy-2026-demo/`. Update the trip page frontmatter inside the new demo source: ```yaml title: 'Italy 2026 (Demo)' slug: italy-2026-demo ``` Create the real page tree at `user/pages/01.trips/italy-2026-demo/` with the standard four subfolders. Update Makefile: - `demo-load`: replace all `italy-2025` references with `italy-2026-demo` - `demo-reset`: replace `rm -rf user/pages/01.trips/italy-2025` with `rm -rf user/pages/01.trips/italy-2026-demo` `italy-2025` is never touched by demo commands after this change. ### 1b. Japan demo retired Remove all `japan-korea-2026` blocks from `demo-load` and `demo-reset`. The source files in `user/docs/demo/trips/japan-korea-2026/` stay on disk as a backup but are not loaded by any make target. The `japan-korea-2026` trip structure and any real content committed there remains untouched. ### 1c. Italy 2025 demo stories removed The 3 Tuscany demo stories currently at `user/pages/01.trips/italy-2025/04.stories/` (if present on disk) are deleted — they are moving to the demo trip. The `04.stories/` folder itself is kept with its `stories.md` index page. --- ## Part 2: Real Trip Page Trees Three trips get the standard structure: `trip.md`, `01.dailies/dailies.md`, `02.map/map.md`, `03.stats/stats.md`, `04.stories/stories.md`. | Slug | Title | Action | |---|---|---| | `central-asia-2023` | Central Asia 2023 | Create new | | `us-canada-mex-2024` | Northern America 2024 | Create new | | `italy-2025` | Cycling Tuscany 2025 | Exists — update title only | All three are committed to the `user/` git repo as permanent content. --- ## Part 3: Pixelfed Import Script ### Location `scripts/pixelfed-import.py` Invoked via: `make pixelfed-import` ### Input `/home/mischa/Nextcloud/Downloads/pixelfed/pixelfed-statuses.json` (36 posts, Pixelfed v1 export format) ### Trip routing by year | `created_at` year | Target trip | |---|---| | 2023 | `central-asia-2023` | | 2024 | `us-canada-mex-2024` | | 2025 | `italy-2025` | Posts are numbered per trip (1-indexed), reset for each trip. ### Output folder structure For each post, one folder inside `user/pages/01.trips/{trip}/01.dailies/`: ``` {YYYY-MM-DD}-pixelfed-{N}.entry/ entry.md photo-1.jpg photo-2.jpg ... ``` Where `N` is the per-trip sequence number and `YYYY-MM-DD` comes from `created_at`. ### Field mapping | Pixelfed field | Grav frontmatter field | Notes | |---|---|---| | `created_at` | `date` | ISO 8601 → `Y-m-d H:i` | | *(generated)* | `title` | `"Pixelfed Import {N}"` | | `place.name` | `location_city` | Empty string if `place` is null | | `place.country` | `location_country` | Empty string if `place` is null | | *(none)* | `lat`, `lng` | Always empty — no coordinate data in export | | *(none)* | `weather_temp_c`, `weather_desc` | Always empty | | first downloaded photo filename | `hero_image` | e.g. `photo-1.jpg` | | `content_text` | body | Already HTML-stripped in export | Fixed frontmatter values: `template: entry`, `published: true`. ### Photo download For each item in `media_attachments`: - Download from `url` field - Save as `photo-{index}.jpg` (1-indexed) regardless of original filename - Use the extension from the `mime` field (`image/png` → `.png`, `image/jpeg` → `.jpg`) - Set `hero_image` in frontmatter to the filename of the first downloaded photo ### Error handling - If a photo download fails, log a warning and continue (do not abort the post) - If the output folder already exists, skip that post (idempotent re-runs) ### Make target ```makefile pixelfed-import: python3 scripts/pixelfed-import.py ``` --- ## File Map | File | Change | |---|---| | `user/docs/demo/trips/italy-2026-demo/` | New — copy of italy-2025 demo source with updated title/slug | | `user/pages/01.trips/italy-2026-demo/` | New — demo trip page tree | | `user/pages/01.trips/italy-2025/trip.md` | Update title to "Cycling Tuscany 2025" | | `user/pages/01.trips/italy-2025/04.stories/` | Remove 3 demo story subfolders | | `user/pages/01.trips/central-asia-2023/` | New — real trip page tree | | `user/pages/01.trips/us-canada-mex-2024/` | New — real trip page tree | | `Makefile` | Update demo-load / demo-reset targets | | `scripts/pixelfed-import.py` | New — one-time import script | --- ## Constraints - Never read `.env` directly - All CSS uses design tokens — script produces no CSS - Import script writes to `user/pages/` only; caller runs `make content-push` afterwards to commit and sync - The `italy-2025` trip must never appear in `demo-load` or `demo-reset` after this change