113 lines
3.5 KiB
TypeScript
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",
|
|
};
|
|
}
|