.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
searx.engines.mullvad_leta Namespace Reference

Classes

class  DataNodeQueryMetaDataIndices
 
class  DataNodeResultIndices
 

Functions

 init (_)
 
 request (str query, dict params)
 
EngineResults response (Response resp)
 
None fetch_traits (EngineTraits engine_traits)
 

Variables

 logger = logging.getLogger()
 
EngineTraits search_url = "https://leta.mullvad.net"
 
dict about
 
list categories = ["general", "web"]
 
bool paging = True
 
int max_page = 10
 
bool time_range_support = True
 
dict time_range_dict
 
 LetaEnginesType = typing.Literal["google", "brave"]
 
LetaEnginesType leta_engine = "google"
 

Detailed Description

Mullvad Leta is a search engine proxy. Currently Leta only offers text
search results not image, news or any other types of search result.  Leta acts
as a proxy to Google and Brave search results. You can select which backend
search engine you wish to use, see  (:py:obj:`leta_engine`).

.. hint::

   Leta caches each search for up to 30 days.  For example, if you use search
   terms like ``news``, contrary to your intention you'll get very old results!


Configuration
=============

The engine has the following additional settings:

- :py:obj:`leta_engine` (:py:obj:`LetaEnginesType`)

You can configure one Leta engine for Google and one for Brave:

.. code:: yaml

  - name: mullvadleta
    engine: mullvad_leta
    leta_engine: google
    shortcut: ml

  - name: mullvadleta brave
    engine: mullvad_leta
    network: mullvadleta  # use network from engine "mullvadleta" configured above
    leta_engine: brave
    shortcut: mlb

Implementations
===============

Function Documentation

◆ fetch_traits()

None searx.engines.mullvad_leta.fetch_traits ( EngineTraits engine_traits)
Fetch languages and regions from Mullvad-Leta

Definition at line 185 of file mullvad_leta.py.

185def fetch_traits(engine_traits: EngineTraits) -> None:
186 """Fetch languages and regions from Mullvad-Leta"""
187
188 def extract_table_data(table):
189 for row in table.xpath(".//tr")[2:]:
190 cells = row.xpath(".//td | .//th") # includes headers and data
191 if len(cells) > 1: # ensure the column exists
192 cell0 = cells[0].text_content().strip()
193 cell1 = cells[1].text_content().strip()
194 yield [cell0, cell1]
195
196 # pylint: disable=import-outside-toplevel
197 # see https://github.com/searxng/searxng/issues/762
198 from searx.network import get as http_get
199
200 # pylint: enable=import-outside-toplevel
201
202 resp = http_get(f"{search_url}/documentation")
203 if not isinstance(resp, Response):
204 print("ERROR: failed to get response from mullvad-leta. Are you connected to the VPN?")
205 return
206 if not resp.ok:
207 print("ERROR: response from mullvad-leta is not OK. Are you connected to the VPN?")
208 return
209
210 dom = html.fromstring(resp.text)
211
212 # There are 4 HTML tables on the documentation page for extracting information:
213 # 0. Keyboard Shortcuts
214 # 1. Query Parameters (shoutout to Mullvad for accessible docs for integration)
215 # 2. Country Codes [Country, Code]
216 # 3. Language Codes [Language, Code]
217 tables = eval_xpath_list(dom.body, "//table")
218 if tables is None or len(tables) <= 0:
219 print("ERROR: could not find any tables. Was the page updated?")
220
221 language_table = tables[3]
222 lang_map = {
223 "zh-hant": "zh_Hans",
224 "zh-hans": "zh_Hant",
225 "jp": "ja",
226 }
227
228 for language, code in extract_table_data(language_table):
229
230 locale_tag = lang_map.get(code, code).replace("-", "_") # type: ignore
231 try:
232 locale = babel.Locale.parse(locale_tag)
233 except babel.UnknownLocaleError:
234 print(f"ERROR: Mullvad-Leta language {language} ({code}) is unknown by babel")
235 continue
236
237 sxng_tag = language_tag(locale)
238 engine_traits.languages[sxng_tag] = code
239
240 country_table = tables[2]
241 country_map = {
242 "cn": "zh-CN",
243 "hk": "zh-HK",
244 "jp": "ja-JP",
245 "my": "ms-MY",
246 "tw": "zh-TW",
247 "uk": "en-GB",
248 "us": "en-US",
249 }
250
251 for country, code in extract_table_data(country_table):
252
253 sxng_tag = country_map.get(code)
254 if sxng_tag:
255 engine_traits.regions[sxng_tag] = code
256 continue
257
258 try:
259 locale = babel.Locale.parse(f"{code.lower()}_{code.upper()}")
260 except babel.UnknownLocaleError:
261 locale = None
262
263 if locale:
264 engine_traits.regions[region_tag(locale)] = code
265 continue
266
267 official_locales = get_official_locales(code, engine_traits.languages.keys(), regional=True)
268 if not official_locales:
269 print(f"ERROR: Mullvad-Leta country '{code}' ({country}) could not be mapped as expected.")
270 continue
271
272 for locale in official_locales:
273 engine_traits.regions[region_tag(locale)] = code

◆ init()

searx.engines.mullvad_leta.init ( _)

Definition at line 90 of file mullvad_leta.py.

90def init(_):
91 l = typing.get_args(LetaEnginesType)
92 if leta_engine not in l:
93 raise ValueError(f"leta_engine '{leta_engine}' is invalid, use one of {', '.join(l)}")
94
95

◆ request()

searx.engines.mullvad_leta.request ( str query,
dict params )

Definition at line 124 of file mullvad_leta.py.

124def request(query: str, params: dict):
125 params["method"] = "GET"
126 args = {
127 "q": query,
128 "engine": leta_engine,
129 "x-sveltekit-invalidated": "001", # hardcoded from all requests seen
130 }
131
132 country = traits.get_region(params.get("searxng_locale"), traits.all_locale) # type: ignore
133 if country:
134 args["country"] = country
135
136 language = traits.get_language(params.get("searxng_locale"), traits.all_locale) # type: ignore
137 if language:
138 args["language"] = language
139
140 if params["time_range"] in time_range_dict:
141 args["lastUpdated"] = time_range_dict[params["time_range"]]
142
143 if params["pageno"] > 1:
144 args["page"] = params["pageno"]
145
146 params["url"] = f"{search_url}/search/__data.json?{urlencode(args)}"
147
148 return params
149
150

◆ response()

EngineResults searx.engines.mullvad_leta.response ( Response resp)

Definition at line 151 of file mullvad_leta.py.

151def response(resp: Response) -> EngineResults:
152 json_response = resp.json()
153
154 nodes = json_response["nodes"]
155 # 0: is None
156 # 1: has "connected=True", not useful
157 # 2: query results within "data"
158
159 data_nodes = nodes[2]["data"]
160 # Instead of nested object structure, all objects are flattened into a
161 # list. Rather, the first object in data_node provides indices into the
162 # "data_nodes" to access each searchresult (which is an object of more
163 # indices)
164 #
165 # Read the relative TypedDict definitions for details
166
167 query_meta_data: DataNodeQueryMetaDataIndices = data_nodes[0]
168
169 query_items_indices = query_meta_data["items"]
170
171 results = EngineResults()
172 for idx in data_nodes[query_items_indices]:
173 query_item_indices: DataNodeResultIndices = data_nodes[idx]
174 results.add(
175 MainResult(
176 url=data_nodes[query_item_indices["link"]],
177 title=data_nodes[query_item_indices["title"]],
178 content=data_nodes[query_item_indices["snippet"]],
179 )
180 )
181
182 return results
183
184

Variable Documentation

◆ about

dict searx.engines.mullvad_leta.about
Initial value:
1= {
2 "website": search_url,
3 "wikidata_id": 'Q47008412', # the Mullvad id - not leta, but related
4 "official_api_documentation": 'https://leta.mullvad.net/faq',
5 "use_official_api": False,
6 "require_api_key": False,
7 "results": 'HTML',
8}

Definition at line 62 of file mullvad_leta.py.

◆ categories

list searx.engines.mullvad_leta.categories = ["general", "web"]

Definition at line 72 of file mullvad_leta.py.

◆ leta_engine

LetaEnginesType searx.engines.mullvad_leta.leta_engine = "google"

Definition at line 86 of file mullvad_leta.py.

◆ LetaEnginesType

searx.engines.mullvad_leta.LetaEnginesType = typing.Literal["google", "brave"]

Definition at line 83 of file mullvad_leta.py.

◆ logger

searx.engines.mullvad_leta.logger = logging.getLogger()

Definition at line 55 of file mullvad_leta.py.

◆ max_page

int searx.engines.mullvad_leta.max_page = 10

Definition at line 74 of file mullvad_leta.py.

◆ paging

bool searx.engines.mullvad_leta.paging = True

Definition at line 73 of file mullvad_leta.py.

◆ search_url

EngineTraits searx.engines.mullvad_leta.search_url = "https://leta.mullvad.net"

Definition at line 59 of file mullvad_leta.py.

◆ time_range_dict

dict searx.engines.mullvad_leta.time_range_dict
Initial value:
1= {
2 "day": "d",
3 "week": "w",
4 "month": "m",
5 "year": "y",
6}

Definition at line 76 of file mullvad_leta.py.

◆ time_range_support

bool searx.engines.mullvad_leta.time_range_support = True

Definition at line 75 of file mullvad_leta.py.