Reiseblog mit CMS

This commit is contained in:
Burkhard Naumann 2026-05-30 00:09:33 +02:00
commit 7f820a6478
19 changed files with 600 additions and 0 deletions

35
src/lib/gpx.js Normal file
View file

@ -0,0 +1,35 @@
import { readdir, readFile } from 'node:fs/promises';
import path from 'node:path';
import { DOMParser } from '@xmldom/xmldom';
import { gpx } from '@tmcw/togeojson';
// Hier landen deine Komoot-/App-Exporte. Dateinamen am besten mit Datum
// beginnen lassen (z. B. 2026-06-01-pyrenaeen.gpx), dann stimmt die Reihenfolge.
const TRACKS_DIR = path.join(process.cwd(), 'src/data/tracks');
// Liest alle .gpx-Dateien und fügt ihre Streckenlinien zu einer
// GeoJSON-FeatureCollection zusammen (= deine Gesamtroute).
export async function loadRoute() {
let files = [];
try {
files = (await readdir(TRACKS_DIR)).filter((f) => f.toLowerCase().endsWith('.gpx'));
} catch {
return { type: 'FeatureCollection', features: [] };
}
files.sort();
const features = [];
for (const file of files) {
const xml = await readFile(path.join(TRACKS_DIR, file), 'utf-8');
const doc = new DOMParser().parseFromString(xml, 'text/xml');
const geo = gpx(doc);
for (const feature of geo.features) {
const type = feature.geometry?.type;
if (type === 'LineString' || type === 'MultiLineString') {
feature.properties = { ...feature.properties, source: file };
features.push(feature);
}
}
}
return { type: 'FeatureCollection', features };
}

43
src/lib/photos.js Normal file
View file

@ -0,0 +1,43 @@
import { readdir, readFile } from 'node:fs/promises';
import path from 'node:path';
import exifr from 'exifr';
// Fotos hier ablegen; sie werden 1:1 ausgeliefert (URL /photos/<datei>).
// Wichtig: Original-Dateien verwenden manche Cloud-/Chat-Dienste löschen die GPS-Daten.
const PHOTOS_DIR = path.join(process.cwd(), 'public/photos');
// Liest aus jedem Foto GPS + Aufnahmezeitpunkt und liefert Karten-Marker.
export async function loadPhotoMarkers() {
let files = [];
try {
files = (await readdir(PHOTOS_DIR)).filter((f) => /\.(jpe?g|tiff?|heic|heif)$/i.test(f));
} catch {
return [];
}
const markers = [];
for (const file of files) {
const buffer = await readFile(path.join(PHOTOS_DIR, file));
let gps = null;
try {
gps = await exifr.gps(buffer);
} catch {
gps = null;
}
if (!gps || gps.latitude == null || gps.longitude == null) continue;
let date = null;
try {
const meta = await exifr.parse(buffer, ['DateTimeOriginal']);
if (meta?.DateTimeOriginal) date = new Date(meta.DateTimeOriginal).toISOString();
} catch {
date = null;
}
markers.push({ file, url: `/photos/${file}`, lat: gps.latitude, lng: gps.longitude, date });
}
markers.sort((a, b) => (a.date ?? '').localeCompare(b.date ?? ''));
return markers;
}