Optimize scan process with quick/deep modes and archive tag merging

Quick scan (default):
- Pre-load all ImportTask records for O(1) duplicate checks
- Batch task creation commits (50 at a time)
- Cache import settings (5-min TTL)
- Skip pHash comparison for speed

Deep scan (on-demand):
- Full reprocessing of all files
- pHash similarity detection
- Optional thumbnail regeneration
- Optional sidecar re-application

Archive tag merging:
- Add archive tags to existing images when duplicates found
- Works for both hash and pHash duplicate detection

Also fixes:
- Add missing source/post tag icons to gallery templates
This commit is contained in:
Bryan Van Deusen
2026-01-31 15:18:43 -05:00
parent d0fcde38e8
commit 042a69f9c3
7 changed files with 595 additions and 171 deletions
+4 -2
View File
@@ -555,11 +555,13 @@
item.appendChild(overlay);
}
// Render tags
// Render tags with icons
overlay.innerHTML = visibleTags.map(t => {
const displayName = getTagDisplayName(t.name, t.kind);
const icon = getTagIcon(t.kind);
const encodedName = encodeURIComponent(t.name);
return `<a class="tag-chip" href="/gallery?tag=${encodedName}" title="Filter by ${escapeHtml(t.name)}" onclick="event.stopPropagation()">${escapeHtml(displayName)}</a>`;
const prefix = icon !== '#' ? icon + ' ' : '#';
return `<a class="tag-chip" href="/gallery?tag=${encodedName}" title="Filter by ${escapeHtml(t.name)}" onclick="event.stopPropagation()">${prefix}${escapeHtml(displayName)}</a>`;
}).join('');
} catch (e) {
+18 -2
View File
@@ -187,6 +187,21 @@
return section;
}
// Tag icon mapping (matches showcase.js and bulk-select.js)
function getTagIcon(kind) {
const icons = {
artist: '🎨',
archive: '🗜️',
character: '👤',
series: '📺',
fandom: '🎭',
rating: '⚠️',
source: '🌐',
post: '📌'
};
return icons[kind] || '#';
}
// Create a single image element
function createImageElement(img) {
const item = document.createElement('div');
@@ -196,12 +211,13 @@
item.dataset.type = img.is_video ? 'video' : 'image';
item.dataset.filename = img.filename;
// Build tag overlay HTML
// Build tag overlay HTML with icons
let tagsHtml = '';
if (img.tags && img.tags.length > 0) {
const tagChips = img.tags.map(t => {
const displayName = t.name.includes(':') ? t.name.split(':')[1] : t.name;
const prefix = t.kind === 'user' ? '#' : '';
const icon = getTagIcon(t.kind);
const prefix = icon !== '#' ? icon + ' ' : '#';
return `<a class="tag-chip" href="/gallery?tag=${encodeURIComponent(t.name)}" title="Filter by ${t.name}" onclick="event.stopPropagation()">${prefix}${displayName}</a>`;
}).join('');
tagsHtml = `<div class="tag-overlay">${tagChips}</div>`;