feat: low-res webp thumbnails for library previews
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNQ8ghPfzAfsyVYd6HgFb6
This commit is contained in:
@@ -66,7 +66,7 @@ export default function LibraryApp() {
|
||||
{items.map((v) => (
|
||||
<article key={v.id} className={`kachel ${sel.has(v.id) ? 'gewaehlt' : ''}`}>
|
||||
<div className="kachel-bild" onClick={() => toggle(v.id)}>
|
||||
<img src={`/api/items/${v.id}/file`} alt="" loading="lazy" />
|
||||
<img src={`/api/items/${v.id}/file?thumb=1`} alt="" loading="lazy" />
|
||||
<span className="haken">{sel.has(v.id) ? '✓' : ''}</span>
|
||||
</div>
|
||||
<input className="name" defaultValue={v.filename || ''} onBlur={(e) => rename(v.id, e.target.value)} />
|
||||
|
||||
@@ -7,15 +7,23 @@ export const prerender = false;
|
||||
// Streamt das Ergebnis- (oder Quell-)Bild aus dem Objektspeicher.
|
||||
export const GET: APIRoute = async ({ params, url, locals }) => {
|
||||
if (!locals.user) return new Response('Unauthorized', { status: 401 });
|
||||
const which = url.searchParams.get('src') === '1' ? 'source_path' : 'result_path';
|
||||
const item = await one<any>(`SELECT ${which} AS path, filename, has_alpha FROM items WHERE id=$1`, [params.id]);
|
||||
if (!item?.path) return new Response('Nicht gefunden', { status: 404 });
|
||||
const q = url.searchParams;
|
||||
const wantThumb = q.get('thumb') === '1';
|
||||
const wantSrc = q.get('src') === '1';
|
||||
const item = await one<any>(
|
||||
`SELECT source_path, result_path, thumb_path, filename, has_alpha FROM items WHERE id=$1`, [params.id]);
|
||||
// Vorschau: Thumbnail bevorzugen, sonst Ergebnis. Quelle nur explizit.
|
||||
const path = wantSrc ? item?.source_path
|
||||
: wantThumb ? (item?.thumb_path || item?.result_path)
|
||||
: item?.result_path;
|
||||
if (!path) return new Response('Nicht gefunden', { status: 404 });
|
||||
try {
|
||||
const buf = await getObject(item.path);
|
||||
const download = url.searchParams.get('download') === '1';
|
||||
const buf = await getObject(path);
|
||||
const download = q.get('download') === '1';
|
||||
const isWebp = path.endsWith('.webp');
|
||||
return new Response(buf, {
|
||||
headers: {
|
||||
'Content-Type': item.has_alpha ? 'image/png' : 'image/png',
|
||||
'Content-Type': isWebp ? 'image/webp' : 'image/png',
|
||||
'Cache-Control': 'private, max-age=300',
|
||||
...(download ? { 'Content-Disposition': `attachment; filename="${item.filename || 'klarbild.png'}"` } : {}),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user