feat: add pixelfed-import script and make target

Copies JSON export + script into Docker container and runs import via
python3; installs python3 if absent. Idempotent (skips existing folders).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
This commit is contained in:
2026-06-20 15:32:56 +02:00
parent 3c4ec0b79b
commit ed005bae14
2 changed files with 113 additions and 0 deletions
+6
View File
@@ -55,6 +55,12 @@ demo-load:
demo-reset: demo-reset:
docker exec intotheeast_grav bash -c "rm -rf /var/www/html/user/pages/01.trips/italy-2026-demo && cd /var/www/html && php bin/grav clearcache" docker exec intotheeast_grav bash -c "rm -rf /var/www/html/user/pages/01.trips/italy-2026-demo && cd /var/www/html && php bin/grav clearcache"
pixelfed-import:
docker exec intotheeast_grav bash -c "which python3 || apt-get install -y python3 --no-install-recommends -q"
docker cp /home/mischa/Nextcloud/Downloads/pixelfed/pixelfed-statuses.json intotheeast_grav:/tmp/pixelfed-statuses.json
docker cp scripts/pixelfed-import.py intotheeast_grav:/tmp/pixelfed-import.py
docker exec -w /var/www/html intotheeast_grav python3 /tmp/pixelfed-import.py
# ── Content sync (user repo ↔ Gitea) ────────────────────────────────────────── # ── Content sync (user repo ↔ Gitea) ──────────────────────────────────────────
content-push: content-push:
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""One-time import of Pixelfed statuses into Grav entry pages."""
import json
import os
import urllib.request
from datetime import datetime, timezone
INPUT_FILE = os.environ.get('PIXELFED_JSON', '/tmp/pixelfed-statuses.json')
USER_PAGES = 'user/pages/01.trips'
TRIP_MAP = {
'2023': 'central-asia-2023',
'2024': 'us-canada-mex-2024',
'2025': 'italy-2025',
}
EXT_MAP = {
'image/jpeg': 'jpg',
'image/png': 'png',
'image/gif': 'gif',
'image/webp': 'webp',
}
ENTRY_TEMPLATE = """\
---
title: '{title}'
date: '{date}'
template: entry
published: true
hero_image: '{hero_image}'
lat: ''
lng: ''
location_city: '{location_city}'
location_country: '{location_country}'
weather_temp_c: ''
weather_desc: ''
---
{body}
"""
def download(url, dest):
try:
urllib.request.urlretrieve(url, dest)
return True
except Exception as exc:
print(f' Warning: download failed {url}: {exc}')
return False
def main():
with open(INPUT_FILE) as f:
posts = json.load(f)
counters = {}
for post in posts:
year = post['created_at'][:4]
trip = TRIP_MAP.get(year)
if not trip:
print(f"Skip: no trip mapping for year {year} (post {post['id']})")
continue
counters[trip] = counters.get(trip, 0) + 1
n = counters[trip]
date_str = post['created_at'][:10] # YYYY-MM-DD
folder = f'{date_str}-pixelfed-{n}.entry'
path = os.path.join(USER_PAGES, trip, '01.dailies', folder)
if os.path.exists(path):
print(f'Skip: {folder} already exists')
continue
os.makedirs(path)
print(f'Creating {trip}/{folder}')
hero_image = ''
for i, att in enumerate(post.get('media_attachments', []), 1):
ext = EXT_MAP.get(att.get('mime', ''), 'jpg')
filename = f'photo-{i}.{ext}'
if download(att['url'], os.path.join(path, filename)) and i == 1:
hero_image = filename
place = post.get('place') or {}
dt = datetime.fromisoformat(post['created_at'].replace('Z', '+00:00'))
date_fmt = dt.strftime('%Y-%m-%d %H:%M')
entry_md = ENTRY_TEMPLATE.format(
title=f'Pixelfed Import {n}',
date=date_fmt,
hero_image=hero_image,
location_city=place.get('name', ''),
location_country=place.get('country', ''),
body=post.get('content_text', '').strip(),
)
with open(os.path.join(path, 'entry.md'), 'w') as f:
f.write(entry_md)
print(f'\nDone. Posts per trip: {counters}')
if __name__ == '__main__':
main()