.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
external_bang.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2# pylint: disable=missing-module-docstring
3
4from urllib.parse import quote_plus, urlparse
5from searx.data import EXTERNAL_BANGS
6
7LEAF_KEY = chr(16)
8
9
10def get_node(external_bangs_db, bang):
11 node = external_bangs_db['trie']
12 after = ''
13 before = ''
14 for bang_letter in bang:
15 after += bang_letter
16 if after in node and isinstance(node, dict):
17 node = node[after]
18 before += after
19 after = ''
20 return node, before, after
21
22
23def get_bang_definition_and_ac(external_bangs_db, bang):
24 node, before, after = get_node(external_bangs_db, bang)
25
26 bang_definition = None
27 bang_ac_list = []
28 if after != '':
29 for k in node:
30 if k.startswith(after):
31 bang_ac_list.append(before + k)
32 elif isinstance(node, dict):
33 bang_definition = node.get(LEAF_KEY)
34 bang_ac_list = [before + k for k in node.keys() if k != LEAF_KEY]
35 elif isinstance(node, str):
36 bang_definition = node
37 bang_ac_list = []
38
39 return bang_definition, bang_ac_list
40
41
42def resolve_bang_definition(bang_definition, query):
43 url, rank = bang_definition.split(chr(1))
44 if url.startswith('//'):
45 url = 'https:' + url
46 if query:
47 url = url.replace(chr(2), quote_plus(query))
48 else:
49 # go to main instead of search page
50 o = urlparse(url)
51 url = o.scheme + '://' + o.netloc
52
53 rank = int(rank) if len(rank) > 0 else 0
54 return (url, rank)
55
56
57def get_bang_definition_and_autocomplete(bang, external_bangs_db=None): # pylint: disable=invalid-name
58 if external_bangs_db is None:
59 external_bangs_db = EXTERNAL_BANGS
60
61 bang_definition, bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang)
62
63 new_autocomplete = []
64 current = [*bang_ac_list]
65 done = set()
66 while len(current) > 0:
67 bang_ac = current.pop(0)
68 done.add(bang_ac)
69
70 current_bang_definition, current_bang_ac_list = get_bang_definition_and_ac(external_bangs_db, bang_ac)
71 if current_bang_definition:
72 _, order = resolve_bang_definition(current_bang_definition, '')
73 new_autocomplete.append((bang_ac, order))
74 for new_bang in current_bang_ac_list:
75 if new_bang not in done and new_bang not in current:
76 current.append(new_bang)
77
78 new_autocomplete.sort(key=lambda t: (-t[1], t[0]))
79 new_autocomplete = list(map(lambda t: t[0], new_autocomplete))
80
81 return bang_definition, new_autocomplete
82
83
84def get_bang_url(search_query, external_bangs_db=None):
85 """
86 Redirects if the user supplied a correct bang search.
87 :param search_query: This is a search_query object which contains preferences and the submitted queries.
88 :return: None if the bang was invalid, else a string of the redirect url.
89 """
90 ret_val = None
91
92 if external_bangs_db is None:
93 external_bangs_db = EXTERNAL_BANGS
94
95 if search_query.external_bang:
96 bang_definition, _ = get_bang_definition_and_ac(external_bangs_db, search_query.external_bang)
97 if bang_definition and isinstance(bang_definition, str):
98 ret_val = resolve_bang_definition(bang_definition, search_query.query)[0]
99
100 return ret_val
get_bang_definition_and_ac(external_bangs_db, bang)
get_bang_url(search_query, external_bangs_db=None)
resolve_bang_definition(bang_definition, query)
get_bang_definition_and_autocomplete(bang, external_bangs_db=None)
get_node(external_bangs_db, bang)