fix: handle non-image modalities across uploads, previews, and filenames (#255)

SnapOtter spans five modalities now, but several code paths still assumed image input.

- dropzone: default to accept-all when no fileFilter is given (image tools still pass one); neutral "supported file types" error text instead of "image files"
- automate (pipelines): accept any modality in the file pickers and dropzones; render modality-aware previews (video player, audio waveform, document/data card) instead of always using ImageViewer/BeforeAfterSlider
- filename sanitizer: extend the double-extension allowlist beyond image extensions to video/audio/document/data so e.g. "report.csv.php" becomes "report.csv"; add tests
- thumbnail route: return 422 for non-rasterisable files (audio, data, non-PDF docs) instead of attempting a doomed Sharp decode
- pool: unknown tools fall back to the "system" pool, not the image pool
- a11y labels: "Previous/Next image", "Image viewer/area/controls/drop zone" are now modality-neutral, across all 21 locales
- copy: bulk-rename default, find-duplicates ZIP name, SSRF user-agent, fetch-urls fallback name, file-details MIME label, URL-import placeholder, help dialog
This commit is contained in:
SnapOtter
2026-06-16 18:04:48 +08:00
committed by GitHub
parent 622c9f98a5
commit 8eee17aeea
29 changed files with 420 additions and 246 deletions
@@ -7,7 +7,7 @@ import { useFileStore } from "@/stores/file-store";
export function BulkRenameSettings() {
const { t } = useTranslation();
const { files, processing, error, setProcessing, setError } = useFileStore();
const [pattern, setPattern] = useState("image-{{index}}");
const [pattern, setPattern] = useState("file-{{index}}");
const [startIndex, setStartIndex] = useState(1);
const [downloadReady, setDownloadReady] = useState(false);
@@ -155,7 +155,7 @@ export function FindDuplicatesSettings() {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "unique-images.zip";
a.download = "unique-files.zip";
a.click();
URL.revokeObjectURL(url);
}, [files, results, bestOverrides]);