rspace-online/modules/rphotos/lib/immich-client.ts

113 lines
3.5 KiB
TypeScript

/**
* Centralized Immich API client for rPhotos.
*
* All calls use the single admin RPHOTOS_API_KEY internally.
* This replaces scattered raw fetch calls in mod.ts.
*/
const IMMICH_BASE = process.env.RPHOTOS_IMMICH_URL || "http://localhost:2284";
const IMMICH_API_KEY = process.env.RPHOTOS_API_KEY || "";
function headers(extra?: Record<string, string>): Record<string, string> {
return { "x-api-key": IMMICH_API_KEY, ...extra };
}
// ── Albums ──
export async function immichCreateAlbum(name: string, description?: string) {
const res = await fetch(`${IMMICH_BASE}/api/albums`, {
method: "POST",
headers: headers({ "Content-Type": "application/json" }),
body: JSON.stringify({ albumName: name, description: description || "" }),
});
if (!res.ok) throw new Error(`Immich createAlbum failed: ${res.status}`);
return res.json() as Promise<{ id: string; albumName: string }>;
}
export async function immichDeleteAlbum(albumId: string) {
const res = await fetch(`${IMMICH_BASE}/api/albums/${albumId}`, {
method: "DELETE",
headers: headers(),
});
if (!res.ok) throw new Error(`Immich deleteAlbum failed: ${res.status}`);
}
export async function immichGetAlbum(albumId: string) {
const res = await fetch(`${IMMICH_BASE}/api/albums/${albumId}`, {
headers: headers(),
});
if (!res.ok) return null;
return res.json();
}
// ── Search ──
export async function immichSearchInAlbum(albumId: string, opts: { size?: number; type?: string } = {}) {
const res = await fetch(`${IMMICH_BASE}/api/search/metadata`, {
method: "POST",
headers: headers({ "Content-Type": "application/json" }),
body: JSON.stringify({
size: opts.size || 50,
order: "desc",
type: opts.type || "IMAGE",
...(albumId ? { albumIds: [albumId] } : {}),
}),
});
if (!res.ok) return { items: [] };
const data = await res.json();
return { items: data.assets?.items || [] };
}
// ── Assets ──
export async function immichUploadAsset(formData: FormData) {
const res = await fetch(`${IMMICH_BASE}/api/assets`, {
method: "POST",
headers: { "x-api-key": IMMICH_API_KEY },
body: formData,
});
if (!res.ok) throw new Error(`Immich upload failed: ${res.status}`);
return res.json() as Promise<{ id: string; status: string }>;
}
export async function immichAddAssetsToAlbum(albumId: string, assetIds: string[]) {
const res = await fetch(`${IMMICH_BASE}/api/albums/${albumId}/assets`, {
method: "PUT",
headers: headers({ "Content-Type": "application/json" }),
body: JSON.stringify({ ids: assetIds }),
});
if (!res.ok) throw new Error(`Immich addAssets failed: ${res.status}`);
return res.json();
}
export async function immichDeleteAssets(assetIds: string[]) {
const res = await fetch(`${IMMICH_BASE}/api/assets`, {
method: "DELETE",
headers: headers({ "Content-Type": "application/json" }),
body: JSON.stringify({ ids: assetIds, force: true }),
});
if (!res.ok) throw new Error(`Immich deleteAssets failed: ${res.status}`);
}
export async function immichGetAssetThumbnail(id: string, size: string = "thumbnail") {
const res = await fetch(`${IMMICH_BASE}/api/assets/${id}/thumbnail?size=${size}`, {
headers: headers(),
});
if (!res.ok) return null;
return {
body: await res.arrayBuffer(),
contentType: res.headers.get("Content-Type") || "image/jpeg",
};
}
export async function immichGetAssetOriginal(id: string) {
const res = await fetch(`${IMMICH_BASE}/api/assets/${id}/original`, {
headers: headers(),
});
if (!res.ok) return null;
return {
body: await res.arrayBuffer(),
contentType: res.headers.get("Content-Type") || "image/jpeg",
};
}