Skip to content

Commit dedf07d

Browse files
committed
Add SearXNG Redirector
1 parent 38657eb commit dedf07d

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

searxng.html

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
---
2+
permalink: /searxng
3+
---
4+
5+
<!DOCTYPE html>
6+
<html>
7+
<head>
8+
<meta charset="utf-8">
9+
<link rel="icon" href="https://searx.space/favicon.png" sizes="any">
10+
<link rel="icon" href="https://searx.space/favicon.svg" type="image/svg+xml">
11+
<link rel="apple-touch-icon" href="https://searx.space/favicon.png">
12+
<title>SearXNG Random Instance Redirector</title>
13+
</head>
14+
<body>
15+
<script type="module">
16+
import { detectAll } from '{{ site.url }}/assets/js/vendor/tinyld.min.js';
17+
18+
const MIN_MONTH_UPTIME = 95;
19+
const FALLBACKS = ['paulgo.io', 'search.im-in.space', 'search.ononoki.org', 'search.undertale.uk', 'searx.bndkt.io', 'searx.oloke.xyz'];
20+
21+
const params = new URLSearchParams(window.location.search);
22+
23+
const loadInstances = async () => {
24+
const fallbacks = FALLBACKS.map(i => `https://${i}/`);
25+
if (params.get('fast') === '1') return fallbacks;
26+
27+
const response = await fetch('https://searx.space/data/instances.json');
28+
if (!response.ok) {
29+
console.log('fallback');
30+
return fallbacks;
31+
}
32+
33+
const instances = (await response.json()).instances;
34+
console.log('instances', instances);
35+
36+
const onion = window.location.host.endsWith('.onion');
37+
const best = Object
38+
.entries(instances)
39+
.filter(([u, i]) => {
40+
try {
41+
const url = new URL(u);
42+
if (onion) {
43+
if (i.network_type !== 'tor') return false;
44+
} else {
45+
if (i.network_type !== 'normal' || url.protocol !== 'https:' || i.tls.grade !== 'A+') return false;
46+
}
47+
return i.uptime.uptimeMonth >= MIN_MONTH_UPTIME && i.uptime.uptimeDay === 100 && !i.analytics && i.engines.duckduckgo?.error_rate < 2 && i.engines.google?.error_rate < 2;
48+
} catch(e) {
49+
return false;
50+
}
51+
})
52+
.map(([u, _]) => u);
53+
54+
console.log('best', best);
55+
return best;
56+
};
57+
58+
const detectLanguage = query => {
59+
const en = 'en';
60+
const allowedLanguages = params.get('allowed_languages');
61+
const only = allowedLanguages ? allowedLanguages.split(',') : [en];
62+
console.log('allowed languages', only);
63+
if (only.length <= 1) return en;
64+
65+
const all = detectAll(query, { only });
66+
console.log('detected languages', all);
67+
68+
const detected = all
69+
.filter(i => i.accuracy > 0.01)
70+
.sort((a, b) => b.accuracy - a.accuracy);
71+
if (detected.length === 0) return en;
72+
73+
return detected[0].lang;
74+
};
75+
76+
const redirect = (url, queryFromForm) => {
77+
params
78+
.entries()
79+
.filter(([k, _]) => k !== 'fast' && k !== 'allowed_languages')
80+
.forEach(([k, v]) => url.searchParams.set(k, v));
81+
url.searchParams.set('language', detectLanguage(params.get('q') || queryFromForm));
82+
if (queryFromForm) {
83+
url.searchParams.set('q', queryFromForm)
84+
window.location.href = url.toString();
85+
} else {
86+
window.location.replace(url.toString());
87+
}
88+
};
89+
90+
const pick = xs => xs[Math.floor(Math.random() * xs.length)];
91+
const targetUrl = new URL(pick(await loadInstances()));
92+
targetUrl.pathname = '/search';
93+
targetUrl.searchParams.set('safesearch', params.get('safesearch') || '0');
94+
95+
if (params.has('q')) {
96+
redirect(targetUrl);
97+
} else {
98+
const pageUrl = window.location.origin + window.location.pathname;
99+
document.body.innerHTML = `<p>This page accepts SearXNG <a target="_blank" href="https://docs.searxng.org/dev/search_api.html">GET parameters</a> and optional parameters:<p><p><ul><li><code>fast=1</code> for hardcoded instances</li><li><code>allowed_languages=en,fr,ru</code> for automatic language filter derived from the query</li></ul></p><p>Example for browser settings (<code>about:preferences#search</code> or <code>chrome://settings/search</code>):</p><p><code>${pageUrl}?q=%s&fast=1&image_proxy=True&categories=images</code></p><p>Use this page locally for the best performance: <code>wget ${pageUrl} -O searxng.html</code></p>`;
100+
101+
const input = document.createElement('input');
102+
input.name = 'q';
103+
input.placeholder = 'Search for...';
104+
input.autocomplete = 'off';
105+
input.autocapitalize = 'none';
106+
input.spellcheck = false;
107+
input.autocorrect = 'off';
108+
input.dir = 'auto';
109+
input.style.width = '99%';
110+
111+
const form = document.createElement('form');
112+
form.addEventListener('submit', event => {
113+
event.preventDefault();
114+
redirect(targetUrl, input.value);
115+
});
116+
117+
form.appendChild(input);
118+
document.body.appendChild(form);
119+
}
120+
</script>
121+
</body>
122+
</html>

0 commit comments

Comments
 (0)