Skip to content

Commit f2c7754

Browse files
committed
Update
1 parent 90eedab commit f2c7754

1 file changed

Lines changed: 67 additions & 21 deletions

File tree

searxng.html

Lines changed: 67 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<link rel="icon" href="https://searx.space/favicon.png" sizes="any">
1010
<link rel="icon" href="https://searx.space/favicon.svg" type="image/svg+xml">
1111
<link rel="apple-touch-icon" href="https://searx.space/favicon.png">
12-
<title>SearXNG Random Instance Redirector</title>
12+
<title>Minimalist SearXNG Redirector</title>
1313
<style>
1414
code { background-color: rgba(128, 128, 128, 0.4); padding: 0.1rem 0.25rem 0.1rem 0.25rem }
1515
.pale { color: #808080 }
@@ -19,6 +19,7 @@
1919
<script type="module">
2020
import { detectAll } from '{{ site.url }}/assets/js/vendor/tinyld.min.js';
2121

22+
const INSTANCES_URL = 'https://searx.space/data/instances.json';
2223
const INSTANCES = ['search.charliewhiskey.net', 'search.im-in.space', 'search.ipsys.bf', 'search.mycotrip.tech', 'search.ononoki.org', 'search.pollorebozado.com', 'search.rowie.at', 'search.system51.co.uk', 'search.undertale.uk', 'search.url4irl.com', 'searx.bndkt.io', 'searx.dresden.network', 'searx.foss.family', 'searx.oloke.xyz', 'searx.ox2.fr', 'searx.party', 'searx.perennialte.ch', 'searx.tiekoetter.com', 'searx.zhenyapav.com', 'searxng.shreven.org']
2324
const LANGUAGES = ['en'];
2425
const TIMEOUT = 5000;
@@ -36,7 +37,7 @@
3637
});
3738
if (params.get('fast') === '1') return instances;
3839

39-
const response = await fetch('https://searx.space/data/instances.json');
40+
const response = await fetch(INSTANCES_URL);
4041
if (!response.ok) {
4142
console.log('failed to load instances');
4243
return instances;
@@ -108,53 +109,73 @@
108109
return xs;
109110
};
110111

111-
const redirect = async (params, queryFromForm) => {
112+
const redirect = async (params, shuffledInstances, queryFromForm) => {
112113
document.body.innerHTML = '<div id="message" class="pale"></div>';
113114
const messageElement = document.querySelector('#message');
114115

115-
const shuffledInstances = await loadAndShuffleInstances(params);
116-
console.log('will be trying instances', shuffledInstances);
117-
118116
const targetUrl = new URL(shuffledInstances[0]);
119117
targetUrl.pathname = '/search';
120-
targetUrl.searchParams.set('safesearch', params.get('safesearch') || '0');
121118

119+
const newParams = new Map;
122120
params
123121
.entries()
124122
.filter(([k, _]) => !CUSTOM_PARAMS.includes(k))
125-
.forEach(([k, v]) => targetUrl.searchParams.set(k, v));
123+
.forEach(([k, v]) => newParams.set(k, v));
126124

127125
const query = queryFromForm || params.get('q') || '';
128-
targetUrl.searchParams.set('language', detectLanguage(query, params));
129-
targetUrl.searchParams.set('q', query);
126+
newParams.set('language', detectLanguage(query, params));
127+
newParams.set('q', query);
128+
newParams.set('safesearch', params.get('safesearch') || '0');
130129

131130
const timeout = Number(params.get('timeout')) || TIMEOUT;
131+
const getMethod = params.get('get') === '1';
132132
for (let i = 0; i < shuffledInstances.length; i++) setTimeout(_ => {
133133
window.stop();
134134
const retryTargetUrl = new URL(targetUrl.toString());
135135
retryTargetUrl.host = new URL(shuffledInstances[i]).host;
136136
if (i > 0) {
137137
messageElement.innerHTML = `Attempt ${i + 1}/${shuffledInstances.length}: ${retryTargetUrl.host}`;
138138
}
139-
const href = retryTargetUrl.toString();
140-
console.log('trying', href);
141-
if (queryFromForm) {
142-
window.location.href = href;
139+
if (getMethod) {
140+
newParams.forEach((value, key) => retryTargetUrl.searchParams.set(key, value));
141+
const href = retryTargetUrl.toString();
142+
console.log('get', href);
143+
if (queryFromForm) {
144+
window.location.href = href;
145+
} else {
146+
window.location.replace(href);
147+
}
143148
} else {
144-
window.location.replace(href);
149+
const href = retryTargetUrl.toString();
150+
console.log('post', href);
151+
const form = document.createElement('form');
152+
form.method = 'POST';
153+
form.action = href;
154+
newParams.forEach((value, key) => {
155+
const input = document.createElement('input');
156+
input.type = 'hidden';
157+
input.name = key;
158+
input.value = value;
159+
form.appendChild(input);
160+
});
161+
document.body.appendChild(form);
162+
form.submit();
163+
document.body.removeChild(form);
145164
}
146165
}, i * timeout);
147166

148167
setTimeout(_ => messageElement.innerHTML = 'Failed', shuffledInstances.length * timeout);
149168
};
150169

151-
const main = _ => {
170+
const main = async _ => {
152171
const params = new URLSearchParams(window.location.hash.split('#')[1] || '');
172+
const shuffledInstances = await loadAndShuffleInstances(params);
173+
console.log('will be trying instances', shuffledInstances);
174+
153175
if (params.has('q')) {
154-
redirect(params);
176+
redirect(params, shuffledInstances);
155177
} else {
156-
const pageUrl = window.location.origin + window.location.pathname;
157-
document.body.innerHTML = `<p>This page redirects to a <a rel="noopener noreferrer nofollow" href="${pageUrl}#q=" onclick="window.location.replace('${pageUrl}#q=')">random SearXNG</a> instance.</p><p>It also supports the <a rel="noopener noreferrer nofollow" target="_blank" href="https://docs.searxng.org/dev/search_api.html">GET parameters</a> (provided as an anchor for privacy) and the optional parameters:<p><p><ul><li><code>languages=en,fr,ru</code> to use automatic language filter derived from the query; default is <code>${LANGUAGES.join(',')}</code></li><li><code>fast=1</code> to force use of predefined instances (instead of fetching them using the <a rel="noopener noreferrer nofollow" target="_blank" href="https://searx.space/data/instances.json">API</a>); default is <code>0</code></li><li><code>instances=search.ononoki.org,searx.bndkt.io</code> to predefine the instances; default is <code>${INSTANCES.join(',')}</code></li><li><code>timeout</code> in milliseconds until attempting the next instance; default is <code>${TIMEOUT}</code></li><li><code>attempts</code> how many instances to try; default is <code>${ATTEMPTS}</code></li></ul></p><p>Example for <strong>browser search engine settings</strong> (<code>about:preferences#search</code> or <code>chrome://settings/search</code>): <code>${pageUrl}#q=%s&fast=1&image_proxy=True&categories=images&languages=en,fr,ru</code>.</p><p>For local use: <code>wget ${pageUrl} -O searxng.html</code>.</p><p>Additionally can be combined with the Violentmonkey <a rel="noopener noreferrer nofollow" target="_blank" href="https://userscripts.codonaft.com/searxng-redirect-on-failure.js">userscript</a> to turn search failures into redirects as well.</p>`;
178+
document.body.innerHTML = '';
158179

159180
const input = document.createElement('input');
160181
input.name = 'q';
@@ -165,21 +186,46 @@
165186
input.autocorrect = 'off';
166187
input.dir = 'auto';
167188
input.style.width = '99%';
189+
input.style.margin = '2rem 0 0 0';
168190

169191
const form = document.createElement('form');
170192
form.addEventListener('submit', event => {
171193
event.preventDefault();
172-
redirect(params, input.value);
194+
redirect(params, shuffledInstances, input.value);
173195
});
174196

175197
form.appendChild(input);
176198
document.body.appendChild(form);
199+
200+
const pageUrl = window.location.origin + window.location.pathname;
201+
const div = document.createElement('div');
202+
div.innerHTML = `
203+
<p>This page redirects to a <a rel="noopener noreferrer nofollow" href="${pageUrl}#q=" onclick="window.location.replace('${pageUrl}#q=')">random SearXNG</a> instance.</p>
204+
<hr>
205+
<p>Example for <strong>browser search engine settings</strong> (<code>about:preferences#search</code> or <code>chrome://settings/search</code>): <code>${pageUrl}#q=%s&fast=1&image_proxy=True&categories=images&languages=en,fr,ru</code>.</p>
206+
<p>Supports the <a rel="noopener noreferrer nofollow" target="_blank" href="https://docs.searxng.org/dev/search_api.html">GET parameters</a> (provided as an anchor for privacy) and the optional parameters:</p>
207+
<ul>
208+
<li><code>languages</code> use automatic language filter derived from the query; comma-separated, default is <code>${LANGUAGES.join(',')}</code></li>
209+
<li><code>get</code> pass parameters to the instance using GET method; default is <code>0</code></li>
210+
<li><code>timeout</code> in milliseconds until attempting the next instance; default is <code>${TIMEOUT}</code></li>
211+
<li><code>attempts</code> how many instances to try; default is <code>${ATTEMPTS}</code></li>
212+
<li><code>fast</code> always use predefined instances (instead of fetching them using the <a rel="noopener noreferrer nofollow" target="_blank" href="${INSTANCES_URL}">API</a>); default is <code>0</code></li>
213+
<li><code>instances</code> predefined instances; comma-separated, default is <code>${INSTANCES.join(',')}</code>.</li>
214+
</ul>
215+
<p>For local use (doesn't require any server): <code>wget ${pageUrl} -O searxng.html</code>.</p>
216+
<p>Additionally can be combined with the Violentmonkey <a rel="noopener noreferrer nofollow" target="_blank" href="https://userscripts.codonaft.com/searxng-redirect-on-failure.js">userscript</a> to turn search failures into redirects as well.</p>
217+
<hr>
218+
<p>Existing alternatives:</p>
219+
<ul>
220+
<li><a rel="noopener" target="_blank" href="https://searx.neocities.org/">Neocities</a></li>
221+
<li><a rel="noopener" target="_blank" href="https://github.com/demostanis/gimmeasearx">gimmeasearx</a></li>
222+
</ul>`;
223+
document.body.appendChild(div);
177224
}
178225
};
179226

180227
window.addEventListener('hashchange', main);
181228
main();
182-
183229
</script>
184230
</body>
185231
</html>

0 commit comments

Comments
 (0)