Reiseblog mit CMS
This commit is contained in:
commit
7f820a6478
19 changed files with 600 additions and 0 deletions
35
src/lib/gpx.js
Normal file
35
src/lib/gpx.js
Normal 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
43
src/lib/photos.js
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue