This commit is contained in:
108
js/index.js
Normal file
108
js/index.js
Normal file
@ -0,0 +1,108 @@
|
||||
const storageType = 'localStorage'
|
||||
|
||||
let data = {}
|
||||
|
||||
const statusEl = document.getElementById('status')
|
||||
const formEl = document.getElementById('search')
|
||||
|
||||
const errors = {
|
||||
missingQuery: new TypeError('Query is missing.'),
|
||||
noFoundInstances: new Error('No instances were found.'),
|
||||
}
|
||||
|
||||
function buildSearchURL (opts = {}) {
|
||||
if (typeof opts.query !== 'string') throw errors.missingQuery
|
||||
if (!('instances' in data)) throw errors.noFoundInstances
|
||||
if (data.instances.length === 0) throw errors.noFoundInstances
|
||||
|
||||
// Random instance
|
||||
const n = Math.floor(Math.random() * data.instances.length)
|
||||
const instanceURL = data.instances[n]
|
||||
|
||||
// Build URL
|
||||
const params = new URLSearchParams({
|
||||
q: opts.query
|
||||
})
|
||||
if (opts.category && opts.category !== 'all') {
|
||||
params.append(`category_${opts.category}`, '')
|
||||
}
|
||||
const url = `${instanceURL}?${params.toString()}`
|
||||
return url
|
||||
}
|
||||
|
||||
// Register event listeners
|
||||
formEl.addEventListener('submit', (event) => {
|
||||
event.preventDefault()
|
||||
location.assign(buildSearchURL({
|
||||
query: formEl.query.value,
|
||||
category: formEl.category.value
|
||||
}))
|
||||
})
|
||||
|
||||
function locallyGetInstances () {
|
||||
if (!(storageType in window)) return []
|
||||
const item = window[storageType].getItem('instances')
|
||||
try {
|
||||
return JSON.parse(item)
|
||||
} catch (_err) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function locallySetInstances () {
|
||||
if (!(storageType in window)) return
|
||||
if (!('instances' in data)) return
|
||||
if (data.instances.length === 0) return
|
||||
window[storageType].setItem(
|
||||
'instances',
|
||||
JSON.stringify(data.instances)
|
||||
)
|
||||
}
|
||||
|
||||
async function remotelyGetInstances () {
|
||||
const instances = await fetch('https://searx.space/data/instances.json')
|
||||
.then((req) => req.json())
|
||||
.then((json) => Object.entries(json.instances))
|
||||
.then((entries) => entries.filter(([_url, details]) => {
|
||||
if (details.network_type !== 'normal') return
|
||||
if (details.uptime == null) return
|
||||
if (details.uptime.uptimeDay !== 100) return
|
||||
return true
|
||||
}))
|
||||
.then((entries) => entries.map(([url]) => url))
|
||||
.catch((err) => {
|
||||
console.error(err)
|
||||
return []
|
||||
})
|
||||
window[storageType].setItem('timestamp', Date.now().toString())
|
||||
return instances
|
||||
}
|
||||
|
||||
// Get local instances
|
||||
data.instances = locallyGetInstances()
|
||||
|
||||
// Fetch remote instances if necessary
|
||||
const timestamp = +window[storageType].getItem('timestamp')
|
||||
if (Date.now() > timestamp + 3_600_000 /* 1 hour */) {
|
||||
const remoteInstances = await remotelyGetInstances()
|
||||
if (remoteInstances.length > 0) {
|
||||
data.instances = remoteInstances
|
||||
locallySetInstances()
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-redirect in presence of search parameters
|
||||
if (location.search.length > 0) {
|
||||
const searchParams = new URLSearchParams(location.search.slice(1))
|
||||
if (searchParams.has('q')) {
|
||||
location.assign(buildSearchURL({
|
||||
query: searchParams.get('q'),
|
||||
category: searchParams.get('in') ?? 'all'
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
statusEl.textContent = `${data.instances.length} instances`
|
||||
if (data.instances.length === 0) {
|
||||
statusEl.classList.add('error')
|
||||
}
|
Reference in New Issue
Block a user