fix: dedupe scan 500 error, SQLite limit crash, add keep-best action
- Replace BigInt hammingDistance with 32-bit popcount — safer (no throw on malformed hashes) and ~10× faster - Make scan() async with setImmediate chunking so the event loop stays responsive on large libraries - Batch getGroups() photo lookup in slices of 900 to stay under SQLite's 999-variable limit - Add POST /api/duplicates/keep-best endpoint: scores by resolution then filesize, soft-deletes the losers, dismisses the pair - DuplicateGroup: green "Keep" badge on the best photo, green "Keep best" button in footer Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
93e16561ec
commit
4f7dd3b49b
6 files changed
+205
-78
No files matched your search
+13
-3
@@ -5,7 +5,7 @@ import fs from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { spawn } from 'child_process';
|
||||
import { openDb } from '../worker/db.js';
|
||||
import { scan, getGroups } from './dedupe.js';
|
||||
import { scan, getGroups, keepBest } from './dedupe.js';
|
||||
import { scanMusicLibrary, initMusicTable, musicScanActive } from '../worker/scanMusic.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
@@ -561,10 +561,10 @@ app.delete('/api/photos/:id/collections/:colId', (req, res) => {
|
||||
|
||||
// ── Duplicates ────────────────────────────────────────────────────────────────
|
||||
|
||||
app.post('/api/dedupe/scan', (_req, res) => {
|
||||
app.post('/api/dedupe/scan', async (_req, res) => {
|
||||
try {
|
||||
const { dedupe_threshold } = db.getSettings();
|
||||
res.json(scan(db, dedupe_threshold));
|
||||
res.json(await scan(db, dedupe_threshold));
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
@@ -592,6 +592,16 @@ app.post('/api/duplicates/dismiss', (req, res) => {
|
||||
res.sendStatus(204);
|
||||
});
|
||||
|
||||
app.post('/api/duplicates/keep-best', (req, res) => {
|
||||
try {
|
||||
const ids = req.body.photoIds;
|
||||
if (!Array.isArray(ids) || ids.length < 2) return badRequest(res, 'photoIds must be array of ≥2');
|
||||
const result = keepBest(db, ids);
|
||||
cache.invalidate();
|
||||
res.json(result);
|
||||
} catch (e) { res.status(500).json({ error: e.message }); }
|
||||
});
|
||||
|
||||
// ── Photo Sync ────────────────────────────────────────────────────────────────
|
||||
|
||||
app.get('/api/sync/stream', (req, res) => {
|
||||
|
||||
Reference in new issue
Block a user