Search filters for size (MB) and file extensions
- 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:
1 parent
95f1d427df
commit
e1392608d8
6 files changed
+110
-2
No files matched your search
+16
-1
@@ -3,6 +3,8 @@
|
||||
|
||||
const $ = (selector) => document.querySelector(selector)
|
||||
const FILTERS = ['readable', 'complete', 'hide_encrypted', 'par2_only']
|
||||
/** Text inputs that narrow a search: size bounds in MB and file extensions. */
|
||||
const FIELDS = ['min_size', 'max_size', 'ext']
|
||||
const SOURCE_LABELS = {
|
||||
stem: 'Filename',
|
||||
subject: 'Subject',
|
||||
@@ -19,6 +21,9 @@ const state = {
|
||||
sort: 'newest',
|
||||
source: '',
|
||||
poster: '',
|
||||
min_size: '',
|
||||
max_size: '',
|
||||
ext: '',
|
||||
readable: false,
|
||||
complete: false,
|
||||
hide_encrypted: false,
|
||||
@@ -90,6 +95,7 @@ function readUrl() {
|
||||
state.sort = params.get('sort') ?? 'newest'
|
||||
state.source = params.get('source') ?? ''
|
||||
state.poster = params.get('poster') ?? ''
|
||||
for (const k of FIELDS) state[k] = params.get(k) ?? ''
|
||||
for (const f of FILTERS) state[f] = params.get(f) === '1'
|
||||
state.release = params.get('release') ? Number(params.get('release')) : null
|
||||
}
|
||||
@@ -100,6 +106,7 @@ function writeUrl(push = false) {
|
||||
if (state.sort !== 'newest') params.set('sort', state.sort)
|
||||
if (state.source) params.set('source', state.source)
|
||||
if (state.poster) params.set('poster', state.poster)
|
||||
for (const k of FIELDS) if (state[k]) params.set(k, state[k])
|
||||
for (const f of FILTERS) if (state[f]) params.set(f, '1')
|
||||
if (state.release) params.set('release', String(state.release))
|
||||
const url = `${location.pathname}${params.size ? `?${params}` : ''}`
|
||||
@@ -110,6 +117,7 @@ function syncControls() {
|
||||
$('#q').value = state.q
|
||||
$('#sort').value = state.sort
|
||||
$('#source').value = state.source
|
||||
for (const k of FIELDS) $(`#${k}`).value = state[k]
|
||||
for (const f of FILTERS) {
|
||||
document.querySelector(`[data-filter="${f}"]`).setAttribute('aria-pressed', String(state[f]))
|
||||
}
|
||||
@@ -130,6 +138,7 @@ function searchParams(page) {
|
||||
if (state.q) params.set('q', state.q)
|
||||
if (state.source) params.set('source', state.source)
|
||||
if (state.poster) params.set('poster', state.poster)
|
||||
for (const k of FIELDS) if (state[k]) params.set(k, state[k])
|
||||
for (const f of FILTERS) if (state[f]) params.set(f, '1')
|
||||
return params
|
||||
}
|
||||
@@ -483,6 +492,12 @@ $('#q').addEventListener('input', (event) => {
|
||||
state.q = event.target.value.trim()
|
||||
scheduleSearch()
|
||||
})
|
||||
for (const k of FIELDS) {
|
||||
$(`#${k}`).addEventListener('input', (event) => {
|
||||
state[k] = event.target.value.trim()
|
||||
scheduleSearch()
|
||||
})
|
||||
}
|
||||
$('#sort').addEventListener('change', (event) => {
|
||||
state.sort = event.target.value
|
||||
writeUrl()
|
||||
@@ -528,7 +543,7 @@ window.addEventListener('popstate', () => {
|
||||
const previous = { ...state }
|
||||
readUrl()
|
||||
syncControls()
|
||||
const searchChanged = ['q', 'sort', 'source', 'poster', ...FILTERS].some((k) => previous[k] !== state[k])
|
||||
const searchChanged = ['q', 'sort', 'source', 'poster', ...FIELDS, ...FILTERS].some((k) => previous[k] !== state[k])
|
||||
if (searchChanged) loadResults()
|
||||
if (state.release && state.release !== previous.release) openRelease(state.release)
|
||||
if (!state.release && previous.release) {
|
||||
|
||||
Reference in new issue
Block a user