feat: add core domain types for Photo Gallery SDK including media items, albums, and annotations
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
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';
|
||||
}
|
||||
Reference in New Issue
Block a user