From a5b3702863781b4699e168c21892d04aece5e01b Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Thu, 4 Jun 2026 17:42:32 -0400 Subject: [PATCH] feat(settings): surface the near-duplicate (pHash) control + reorder import tab MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The phash_threshold knob (controls whether edits/variants of an image are dropped as near-duplicates on import) was buried at the bottom of the import filters form and labelled opaquely, so it read as 'missing'. Hoist it to the TOP of the form as a 'Near-duplicate sensitivity' section: a labelled slider (Exact / Strict / Default / Loose stops, 0-16) for the gist + the precise number field, both bound to phash_threshold, with copy that says plainly to lower it if variants are being dropped. Also swap the import-tab order to filters → trigger → recent-tasks (filters on top per operator); the task list stays directly under the trigger for hit/miss feedback adjacency. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../components/settings/ImportFiltersForm.vue | 54 ++++++++++++++++--- frontend/src/views/SettingsView.vue | 11 ++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/settings/ImportFiltersForm.vue b/frontend/src/components/settings/ImportFiltersForm.vue index af06321..c538b35 100644 --- a/frontend/src/components/settings/ImportFiltersForm.vue +++ b/frontend/src/components/settings/ImportFiltersForm.vue @@ -2,6 +2,42 @@ Import filters + +
+
Near-duplicate sensitivity
+
+ How aggressively imports merge look-alike images (perceptual-hash + distance). Lower it if edits/variants of the same image are + being dropped as duplicates; raise it to collapse more + look-alikes. Applies to new imports. +
+ + + + + + + + +
+ + + - - -
Higher = looser near-duplicate matching.
-
@@ -66,6 +94,9 @@ import { reactive, watch } from 'vue' import { useImportStore } from '../../stores/import.js' const store = useImportStore() +// Labelled stops so the less-initiated get the gist without knowing what a +// Hamming distance is. 0 = byte-for-byte only; 10 = the shipped default. +const PHASH_TICKS = { 0: 'Exact', 4: 'Strict', 10: 'Default', 16: 'Loose' } // Downloader + schedule-defaults fields moved to // /subscriptions?tab=settings (operator decision 2026-05-27). This form // now only owns image-import filters. @@ -89,4 +120,11 @@ async function save() { color: rgb(var(--v-theme-on-surface-variant)); margin-top: 2px; } +.fc-phash__title { + font-size: 0.95rem; + font-weight: 600; + color: rgb(var(--v-theme-on-surface)); +} +/* Headroom so the tick labels (Exact/Strict/Default/Loose) aren't clipped. */ +.fc-phash__slider { margin-bottom: 18px; } diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 2c71806..2a2a977 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -44,14 +44,15 @@ - + + + - - -- 2.52.0