Files
immich-folio/app/api/admin/albums/route.ts
Ralksta a3a6319c29 release: v0.16.0
See CHANGELOG.md for the full v0.16.0 entry.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Ralf <rohlenbo79@gmail.com>
Co-authored-by: Paul Thies <110185070+ImScheinox@users.noreply.github.com>
Co-authored-by: lancetm714 <108419425+lancetm714@users.noreply.github.com>
2026-09-22 14:12:13 +02:00

72 lines
2.5 KiB
TypeScript

import { NextResponse } from 'next/server';
import { withAdmin } from '@/lib/admin/withAdmin';
import { getConfig } from '@/lib/config';
interface ImmichAlbumSummary {
id: string;
albumName: string;
/** Immich's own flag. Absent on older versions, which is not the same as false. */
shared?: boolean;
description: string;
albumThumbnailAssetId: string | null;
assetCount: number;
createdAt: string;
updatedAt: string;
}
/** GET: List ALL shared Immich albums (not just allowlisted ones). */
export const GET = withAdmin(async () => {
const config = getConfig();
// Credentials, not `needsSetup`: this route is how the operator picks the
// albums that gallery.yaml is built from, so refusing to run until that file
// exists is a deadlock (#507).
if (config.needsCredentials) {
return NextResponse.json({ error: 'Immich not configured' }, { status: 503 });
}
try {
const res = await fetch(`${config.immich.apiUrl}/albums?shared=true`, {
headers: {
'x-api-key': config.immich.apiKey,
Accept: 'application/json',
},
});
if (!res.ok) {
return NextResponse.json({ error: `Immich API returned ${res.status}` }, { status: 502 });
}
const albums = (await res.json()) as ImmichAlbumSummary[];
// Mark which albums are already configured
const configuredIds = new Set(config.albums);
const enriched = albums.map((album) => ({
id: album.id,
albumName: album.albumName,
description: album.description || '',
thumbnailAssetId: album.albumThumbnailAssetId,
assetCount: album.assetCount,
createdAt: album.createdAt,
updatedAt: album.updatedAt,
isConfigured: configuredIds.has(album.id),
// Immich ignores ?shared=true and returns everything, so this list is the
// whole library rather than the shared part of it (#515). Passing the flag
// through lets the picker say which albums Immich still considers private
// — the accident-prevention the filter was supposed to give, without
// taking away the ability to publish them.
shared: album.shared,
}));
// Sort: configured first, then by name
enriched.sort((a, b) => {
if (a.isConfigured !== b.isConfigured) return a.isConfigured ? -1 : 1;
return a.albumName.localeCompare(b.albumName);
});
return NextResponse.json({ albums: enriched });
} catch (err) {
console.error('[Admin] Failed to fetch albums from Immich:', err);
return NextResponse.json({ error: 'Failed to connect to Immich' }, { status: 502 });
}
});