Files

53 lines
1.7 KiB
TypeScript

import type { MediaItem } from '../types';
/** Trigger a browser download of a single media item by URL. */
export function downloadMedia(item: MediaItem): void {
if (typeof document === 'undefined') return;
const a = document.createElement('a');
a.href = item.src;
a.download = sanitizeFilename(item.name);
a.rel = 'noopener';
document.body.appendChild(a);
a.click();
a.remove();
}
/** Export a metadata-only JSON sidecar for the current selection. */
export function exportMetadata(items: MediaItem[]): void {
if (typeof document === 'undefined') return;
const payload = items.map((i) => ({
name: i.name,
takenAt: new Date(i.takenAt).toISOString(),
source: i.source,
tags: i.tags,
objects: i.objectLabels,
location: i.location,
favorite: i.favorite,
width: i.width,
height: i.height,
}));
const blob = new Blob([JSON.stringify(payload, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'photos-metadata.json';
document.body.appendChild(a);
a.click();
a.remove();
setTimeout(() => URL.revokeObjectURL(url), 1000);
}
/**
* Sanitize a filename to prevent path traversal / illegal characters when it is
* used as a download target. Security-relevant: never trust an imported name.
*/
export function sanitizeFilename(name: string): string {
const cleaned = name
// Strip path separators and characters illegal on common filesystems.
.replace(/[/\\?%*:|"<>]/g, '_')
// Collapse parent-directory sequences (path traversal guard).
.replace(/\.\.+/g, '_')
.trim();
return cleaned.slice(0, 200) || 'photo';
}