Search filters for size (MB) and file extensions
Test and deploy / test (push) Successful in 1m27s
Test and deploy / deploy (push) Successful in 2m9s

- API: min_size and max_size in MB, ext as a comma-separated list. An
  extension matches as a whole word in search_text (file and entry names,
  dots as spaces), so "iso" finds .iso files but not "ISOLATION", which a
  plain search word matched as a substring. The trigram index serves it.
- Web UI: a size range and an extension field in the filter row, kept in
  the URL like the other filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Daan MeijerandClaude Opus 5.5 committed 2026-10-04 19:43:55 +02:00
1 parent 95f1d427df
commit e1392608d8
6 files changed
+110 -2

No files matched your search

+20
View File
@@ -45,6 +45,11 @@ export interface SearchParams {
hideContainers?: boolean
/** Include incomplete releases that consist of par2 files only (hidden by default). */
includePar2Only?: boolean
/** Size bounds in bytes (releases without a known size never match). */
minSize?: number
maxSize?: number
/** File extensions (without the dot); a release matches if a file or archive entry has one of them. */
extensions?: string[]
/** Count matches up to this many past the page (default COUNT_LIMIT); `total` is capped there. */
countLimit?: number
}
@@ -112,6 +117,21 @@ class SearchService {
bindings.push(`%${word.replace(/[\\%_]/g, (c) => `\\${c}`)}%`)
}
if (params.readable) where.push('is_readable_name(r.name)')
if (params.minSize !== undefined) {
where.push('r.size >= ?')
bindings.push(params.minSize)
}
if (params.maxSize !== undefined) {
where.push('r.size <= ?')
bindings.push(params.maxSize)
}
// search_text holds file and entry names with dots as spaces, so an
// extension is a whole word there ("iso" but not "isolation").
const extensions = (params.extensions ?? []).map((e) => e.toLowerCase().replace(/^\./, '')).filter((e) => /^[a-z0-9]{1,8}$/.test(e)).slice(0, 8)
if (extensions.length > 0) {
where.push(`r.search_text ~ ?`)
bindings.push(`(^| )(${extensions.join('|')})( |$)`)
}
if (params.hideEncrypted) where.push('(r.encrypted IS NOT TRUE OR r.password IS NOT NULL)')
if (params.hideContainers) where.push('r.container IS NULL')
// par2 files whose data never arrived (e.g. uploads spread over groups we can't fetch).