fix: unique, chronologically sortable result filenames
Two badges of the same person, same format, same day produced the same filename -- `2026-07-23_lea_the-frame.png` -- and the second upload silently overwrote the first at Picdrop. The name now carries the time down to the second and a short tag derived from the item id: 2026-08-20_143207_lea-badge_the-frame_a3f9.jpg The timestamp leads, so any file listing sorts chronologically on its own. The tag is derived, not random, so re-running the backfill is idempotent. Timestamps use Europe/Berlin (KLARBILD_TZ) rather than UTC -- a picture taken at 00:30 should not be dated to the previous day. Naming moved into its own dependency-free module so the rules are testable and identical everywhere. The generator strips its own stamp when a result is fed back in as a source, so names cannot accumulate. Backfill for the existing library in Admin -> Dateinamen: preview first, then apply. It re-stamps from `created_at` and the item id, keeping the motif and format already chosen, and leaves the stored files alone -- they live under their id, not their name. A separate button re-delivers everything under the new name; the old copies stay put at the destination, since deleting a customer's files automatically is the wrong reflex. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BNhLunz586g6DeYMa7Qsd1
This commit is contained in:
7 files changed
+460
-42
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { storageStats, runRetention, purgeSources, mirrorAllToNas, rebuildThumbs } from '../../../lib/maintenance';
|
||||
import { renameLibrary, redeliverAll } from '../../../lib/renames';
|
||||
import { one } from '../../../lib/db';
|
||||
|
||||
export const prerender = false;
|
||||
@@ -8,12 +9,16 @@ const json = (b: unknown, s = 200) =>
|
||||
|
||||
export const GET: APIRoute = async () => json({ stats: await storageStats() });
|
||||
|
||||
// POST { action: 'retention' | 'purge_sources' }
|
||||
// POST { action: 'retention' | 'purge_sources' | 'rename_preview' | 'rename_apply' | 'redeliver_all' | … }
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const b = await request.json().catch(() => ({}));
|
||||
if (b.action === 'purge_sources') return json(await purgeSources());
|
||||
if (b.action === 'mirror_all') return json(await mirrorAllToNas());
|
||||
if (b.action === 'rebuild_thumbs') return json(await rebuildThumbs());
|
||||
// Eindeutige Dateinamen: erst zeigen, was passieren würde, dann anwenden.
|
||||
if (b.action === 'rename_preview') return json(await renameLibrary(true));
|
||||
if (b.action === 'rename_apply') return json(await renameLibrary(false));
|
||||
if (b.action === 'redeliver_all') return json(await redeliverAll());
|
||||
if (b.action === 'retention') {
|
||||
const s = await one<{ retention_days: number | null }>('SELECT retention_days FROM settings WHERE id=1');
|
||||
if (!s?.retention_days) return json({ error: 'Keine Aufbewahrungsfrist gesetzt.' }, 400);
|
||||
|
||||
Reference in new issue
Block a user