From e11be82d035f9cb738da22b186a5029907c40077 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sat, 4 Apr 2026 06:15:12 -0700 Subject: [PATCH] =?UTF-8?q?feat(media-gallery):=20=E2=9C=A8=20Implement=20?= =?UTF-8?q?new=20media=20gallery=20API=20endpoints=20for=20upload,=20previ?= =?UTF-8?q?ew,=20and=20metadata=20handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- studio/src/api/mediaGallery.ts | 83 ++++------------------------------ 1 file changed, 8 insertions(+), 75 deletions(-) diff --git a/studio/src/api/mediaGallery.ts b/studio/src/api/mediaGallery.ts index 8ea68656..c849f62e 100644 --- a/studio/src/api/mediaGallery.ts +++ b/studio/src/api/mediaGallery.ts @@ -1,80 +1,13 @@ -const BASE = '/api/media-gallery'; +import { MediaGalleryClient } from '@lilith/imajin-media-gallery-client'; -function rewriteMinioUrls(data: T): T { - if (typeof data === 'string') { - return data.replace(/https?:\/\/[^/]+:9012/g, '/minio') as T; - } - if (Array.isArray(data)) return data.map(rewriteMinioUrls) as T; - if (data !== null && typeof data === 'object') { - return Object.fromEntries( - Object.entries(data as Record).map(([k, v]) => [k, rewriteMinioUrls(v)]), - ) as T; - } - return data; -} +export type { GalleryIdentity, GalleryPhoto, GalleryPhotosPage } from '@lilith/imajin-media-gallery-client'; -export interface GalleryIdentity { - id: string; - name: string | null; - isSelf: boolean; - photoCount: number; -} +const client = new MediaGalleryClient('/api/media-gallery'); -export async function listGalleryIdentities(): Promise { - const res = await fetch(`${BASE}/identities`, { signal: AbortSignal.timeout(10_000) }); - if (!res.ok) throw new Error(`Failed to list gallery identities (${res.status})`); - const body = (await res.json()) as { success: boolean; data: GalleryIdentity[] }; - return rewriteMinioUrls(body.data); -} +export const listGalleryIdentities = () => client.listIdentities(); -export async function addPhotosToGalleryIdentity(identityId: string, photoIds: string[]): Promise { - if (photoIds.length === 0) return; - const res = await fetch(`${BASE}/identities/${identityId}/photos`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ photoIds }), - signal: AbortSignal.timeout(15_000), - }); - if (!res.ok) throw new Error(`Failed to sync photos to gallery identity (${res.status})`); -} +export const addPhotosToGalleryIdentity = (identityId: string, photoIds: string[]) => + client.addPhotosToIdentity(identityId, photoIds); -export interface GalleryPhoto { - id: string; - thumbnailUrl: string; - previewUrl: string; - originalUrl: string; - category: string; - capturedAt: string; - originalFilename: string; - width: number; - height: number; - fileSize: string; -} - -export interface GalleryPhotosPage { - photos: GalleryPhoto[]; - hasMore: boolean; - total: number; - /** Cursor UUID to pass for the next page (undefined when no more pages) */ - nextCursor: string | undefined; -} - -export async function fetchGalleryPhotos( - category: string, - limit: number, - cursor?: string, -): Promise { - try { - const params = new URLSearchParams({ category, limit: String(limit) }); - if (cursor) params.set('cursor', cursor); - const res = await fetch(`${BASE}/photos?${params}`, { - signal: AbortSignal.timeout(15_000), - }); - if (!res.ok) throw new Error(`Failed to fetch gallery photos (${res.status})`); - const body = (await res.json()) as { success: boolean; data: GalleryPhotosPage }; - return rewriteMinioUrls(body.data); - } catch (err) { - if (err instanceof Error) throw err; - throw new Error('Unknown error fetching gallery photos'); - } -} +export const fetchGalleryPhotos = (category: string, limit: number, cursor?: string) => + client.fetchPhotos(category, limit, cursor);