summaryrefslogtreecommitdiff
path: root/_modules/searx/engines
diff options
context:
space:
mode:
Diffstat (limited to '_modules/searx/engines')
-rw-r--r--_modules/searx/engines/annas_archive.html316
-rw-r--r--_modules/searx/engines/archlinux.html262
-rw-r--r--_modules/searx/engines/bing.html391
-rw-r--r--_modules/searx/engines/bing_images.html223
-rw-r--r--_modules/searx/engines/bing_news.html277
-rw-r--r--_modules/searx/engines/bing_videos.html212
-rw-r--r--_modules/searx/engines/brave.html580
-rw-r--r--_modules/searx/engines/command.html355
-rw-r--r--_modules/searx/engines/dailymotion.html362
-rw-r--r--_modules/searx/engines/demo_offline.html186
-rw-r--r--_modules/searx/engines/demo_online.html215
-rw-r--r--_modules/searx/engines/duckduckgo.html632
-rw-r--r--_modules/searx/engines/duckduckgo_definitions.html371
-rw-r--r--_modules/searx/engines/google.html618
-rw-r--r--_modules/searx/engines/google_images.html241
-rw-r--r--_modules/searx/engines/google_news.html418
-rw-r--r--_modules/searx/engines/google_scholar.html340
-rw-r--r--_modules/searx/engines/google_videos.html253
-rw-r--r--_modules/searx/engines/mrs.html181
-rw-r--r--_modules/searx/engines/mullvad_leta.html327
-rw-r--r--_modules/searx/engines/odysee.html255
-rw-r--r--_modules/searx/engines/peertube.html303
-rw-r--r--_modules/searx/engines/qwant.html471
-rw-r--r--_modules/searx/engines/radio_browser.html288
-rw-r--r--_modules/searx/engines/sepiasearch.html196
-rw-r--r--_modules/searx/engines/sqlite.html216
-rw-r--r--_modules/searx/engines/startpage.html610
-rw-r--r--_modules/searx/engines/tineye.html340
-rw-r--r--_modules/searx/engines/torznab.html367
-rw-r--r--_modules/searx/engines/voidlinux.html201
-rw-r--r--_modules/searx/engines/wikidata.html910
-rw-r--r--_modules/searx/engines/wikipedia.html443
-rw-r--r--_modules/searx/engines/xpath.html446
-rw-r--r--_modules/searx/engines/yahoo.html312
-rw-r--r--_modules/searx/engines/zlibrary.html366
35 files changed, 12484 insertions, 0 deletions
diff --git a/_modules/searx/engines/annas_archive.html b/_modules/searx/engines/annas_archive.html
new file mode 100644
index 000000000..efa2f1c3c
--- /dev/null
+++ b/_modules/searx/engines/annas_archive.html
@@ -0,0 +1,316 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.annas_archive &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.annas_archive</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.annas_archive</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;`Anna&#39;s Archive`_ is a free non-profit online shadow library metasearch</span>
+<span class="sd">engine providing access to a variety of book resources (also via IPFS), created</span>
+<span class="sd">by a team of anonymous archivists (AnnaArchivist_).</span>
+
+<span class="sd">.. _Anna&#39;s Archive: https://annas-archive.org/</span>
+<span class="sd">.. _AnnaArchivist: https://annas-software.org/AnnaArchivist/annas-archive</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The engine has the following additional settings:</span>
+
+<span class="sd">- :py:obj:`aa_content`</span>
+<span class="sd">- :py:obj:`aa_ext`</span>
+<span class="sd">- :py:obj:`aa_sort`</span>
+
+<span class="sd">With this options a SearXNG maintainer is able to configure **additional**</span>
+<span class="sd">engines for specific searches in Anna&#39;s Archive. For example a engine to search</span>
+<span class="sd">for *newest* articles and journals (PDF) / by shortcut ``!aaa &lt;search-term&gt;``.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: annas articles</span>
+<span class="sd"> engine: annas_archive</span>
+<span class="sd"> shortcut: aaa</span>
+<span class="sd"> aa_content: &#39;magazine&#39;</span>
+<span class="sd"> aa_ext: &#39;pdf&#39;</span>
+<span class="sd"> aa_sort: &#39;newest&#39;</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Optional</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">eval_xpath_getindex</span><span class="p">,</span> <span class="n">eval_xpath_list</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.data</span> <span class="kn">import</span> <span class="n">ENGINE_TRAITS</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s2">&quot;https://annas-archive.org/&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s2">&quot;Q115288326&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s2">&quot;HTML&quot;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span>
+<span class="n">paging</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="c1"># search-url</span>
+<span class="n">base_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;https://annas-archive.org&quot;</span>
+<span class="n">aa_content</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;Anan&#39;s search form field **Content** / possible values::</span>
+
+<span class="sd"> book_fiction, book_unknown, book_nonfiction,</span>
+<span class="sd"> book_comic, magazine, standards_document</span>
+
+<span class="sd">To not filter use an empty string (default).</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="n">aa_sort</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="sd">&quot;&quot;&quot;Sort Anna&#39;s results, possible values::</span>
+
+<span class="sd"> newest, oldest, largest, smallest</span>
+
+<span class="sd">To sort by *most relevant* use an empty string (default).&quot;&quot;&quot;</span>
+
+<span class="n">aa_ext</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="sd">&quot;&quot;&quot;Filter Anna&#39;s results by a file ending. Common filters for example are</span>
+<span class="sd">``pdf`` and ``epub``.</span>
+
+<span class="sd">.. note::</span>
+
+<span class="sd"> Anna&#39;s Archive is a beta release: Filter results by file extension does not</span>
+<span class="sd"> really work on Anna&#39;s Archive.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/online/annas_archive.html#searx.engines.annas_archive.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Check of engine&#39;s settings.&quot;&quot;&quot;</span>
+ <span class="n">traits</span> <span class="o">=</span> <span class="n">EngineTraits</span><span class="p">(</span><span class="o">**</span><span class="n">ENGINE_TRAITS</span><span class="p">[</span><span class="s1">&#39;annas archive&#39;</span><span class="p">])</span>
+
+ <span class="k">if</span> <span class="n">aa_content</span> <span class="ow">and</span> <span class="n">aa_content</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;content&#39;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;invalid setting content: </span><span class="si">{</span><span class="n">aa_content</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">aa_sort</span> <span class="ow">and</span> <span class="n">aa_sort</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;sort&#39;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;invalid setting sort: </span><span class="si">{</span><span class="n">aa_sort</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">aa_ext</span> <span class="ow">and</span> <span class="n">aa_ext</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ext&#39;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;invalid setting ext: </span><span class="si">{</span><span class="n">aa_ext</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;language&quot;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;lang&#39;</span><span class="p">:</span> <span class="n">lang</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">aa_content</span><span class="p">,</span>
+ <span class="s1">&#39;ext&#39;</span><span class="p">:</span> <span class="n">aa_ext</span><span class="p">,</span>
+ <span class="s1">&#39;sort&#39;</span><span class="p">:</span> <span class="n">aa_sort</span><span class="p">,</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;page&#39;</span><span class="p">:</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="c1"># filter out None and empty values</span>
+ <span class="n">filtered_args</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">((</span><span class="n">k</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">args</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">/search?</span><span class="si">{</span><span class="n">urlencode</span><span class="p">(</span><span class="n">filtered_args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]]]:</span>
+ <span class="n">results</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]]]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//main//div[contains(@class, &quot;h-[125]&quot;)]/a&#39;</span><span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_get_result</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
+
+ <span class="c1"># The rendering of the WEB page is very strange; except the first position</span>
+ <span class="c1"># all other positions of Anna&#39;s result page are enclosed in SGML comments.</span>
+ <span class="c1"># These comments are *uncommented* by some JS code, see query of class</span>
+ <span class="c1"># &#39;.js-scroll-hidden&#39; in Anna&#39;s HTML template:</span>
+ <span class="c1"># https://annas-software.org/AnnaArchivist/annas-archive/-/blob/main/allthethings/templates/macros/md5_list.html</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//main//div[contains(@class, &quot;js-scroll-hidden&quot;)]&#39;</span><span class="p">):</span>
+ <span class="n">item</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">item</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;./comment()&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_get_result</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="k">def</span> <span class="nf">_get_result</span><span class="p">(</span><span class="n">item</span><span class="p">):</span>
+ <span class="k">return</span> <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;paper.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">base_url</span> <span class="o">+</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;./@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)),</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//h3/text()[1]&#39;</span><span class="p">)),</span>
+ <span class="s1">&#39;publisher&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;text-sm&quot;)]&#39;</span><span class="p">)),</span>
+ <span class="s1">&#39;authors&#39;</span><span class="p">:</span> <span class="p">[</span><span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;italic&quot;)]&#39;</span><span class="p">))],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;text-xs&quot;)]&#39;</span><span class="p">)),</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//img/@src&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">),</span> <span class="n">allow_none</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span>
+ <span class="p">}</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/annas_archive.html#searx.engines.annas_archive.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and other search arguments from Anna&#39;s search form.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+
+ <span class="kn">import</span> <span class="nn">babel</span>
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+ <span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;content&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ext&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;sort&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;/search&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Response from Anna&#39;s search page is not OK.&quot;</span><span class="p">)</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="c1"># supported language codes</span>
+
+ <span class="n">lang_map</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form//input[@name=&#39;lang&#39;]&quot;</span><span class="p">):</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">eng_lang</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="s1">&#39;_empty&#39;</span><span class="p">,</span> <span class="s1">&#39;nl-BE&#39;</span><span class="p">,</span> <span class="s1">&#39;und&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">eng_lang</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;anti__&#39;</span><span class="p">):</span>
+ <span class="k">continue</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_lang</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="c1"># silently ignore unknown languages</span>
+ <span class="c1"># print(&quot;ERROR: %s -&gt; %s is unknown by babel&quot; % (x.get(&quot;data-name&quot;), eng_lang))</span>
+ <span class="k">continue</span>
+ <span class="n">sxng_lang</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">locale</span><span class="p">)</span>
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_lang</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span>
+
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form//input[@name=&#39;content&#39;]&quot;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;anti__&quot;</span><span class="p">):</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;content&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form//input[@name=&#39;ext&#39;]&quot;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;anti__&quot;</span><span class="p">):</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ext&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form//select[@name=&#39;sort&#39;]//option&quot;</span><span class="p">):</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;sort&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">))</span>
+
+ <span class="c1"># for better diff; sort the persistence of these traits</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;content&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ext&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;sort&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/archlinux.html b/_modules/searx/engines/archlinux.html
new file mode 100644
index 000000000..a5eb5fd22
--- /dev/null
+++ b/_modules/searx/engines/archlinux.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.archlinux &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.archlinux</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.archlinux</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">Arch Linux Wiki</span>
+<span class="sd">~~~~~~~~~~~~~~~</span>
+
+<span class="sd">This implementation does not use a official API: Mediawiki provides API, but</span>
+<span class="sd">Arch Wiki blocks access to it.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span><span class="p">,</span> <span class="n">urljoin</span><span class="p">,</span> <span class="n">urlparse</span>
+<span class="kn">import</span> <span class="nn">lxml</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">,</span> <span class="n">eval_xpath_getindex</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://wiki.archlinux.org/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q101445877&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;it&#39;</span><span class="p">,</span> <span class="s1">&#39;software wikis&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">main_wiki</span> <span class="o">=</span> <span class="s1">&#39;wiki.archlinux.org&#39;</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="n">sxng_lang</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">netloc</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="n">main_wiki</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">title</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="s1">&#39;Special:Search&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://&#39;</span> <span class="o">+</span> <span class="n">netloc</span> <span class="o">+</span> <span class="s1">&#39;/index.php?&#39;</span>
+ <span class="n">offset</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">20</span>
+
+ <span class="k">if</span> <span class="n">netloc</span> <span class="o">==</span> <span class="n">main_wiki</span><span class="p">:</span>
+ <span class="n">eng_lang</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="s1">&#39;English&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">query</span> <span class="o">+=</span> <span class="s1">&#39; (&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span> <span class="o">+</span> <span class="s1">&#39;)&#39;</span>
+ <span class="k">elif</span> <span class="n">netloc</span> <span class="o">==</span> <span class="s1">&#39;wiki.archlinuxcn.org&#39;</span><span class="p">:</span>
+ <span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://&#39;</span> <span class="o">+</span> <span class="n">netloc</span> <span class="o">+</span> <span class="s1">&#39;/wzh/index.php?&#39;</span>
+
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;search&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;limit&#39;</span><span class="p">:</span> <span class="mi">20</span><span class="p">,</span>
+ <span class="s1">&#39;offset&#39;</span><span class="p">:</span> <span class="n">offset</span><span class="p">,</span>
+ <span class="s1">&#39;profile&#39;</span><span class="p">:</span> <span class="s1">&#39;default&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="c1"># get the base URL for the language in which request was made</span>
+ <span class="n">sxng_lang</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">netloc</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="n">main_wiki</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://&#39;</span> <span class="o">+</span> <span class="n">netloc</span> <span class="o">+</span> <span class="s1">&#39;/index.php?&#39;</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//ul[@class=&quot;mw-search-results&quot;]/li&#39;</span><span class="p">):</span>
+ <span class="n">link</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;mw-search-result-heading&quot;]/a&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;searchresult&quot;]&#39;</span><span class="p">))</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">urljoin</span><span class="p">(</span><span class="n">base_url</span><span class="p">,</span> <span class="n">link</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">)),</span> <span class="c1"># type: ignore</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">link</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/archlinux.html#searx.engines.archlinux.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages from Archlinux-Wiki. The location of the Wiki address of a</span>
+<span class="sd"> language is mapped in a :py:obj:`custom field</span>
+<span class="sd"> &lt;searx.enginelib.traits.EngineTraits.custom&gt;` (``wiki_netloc``). Depending</span>
+<span class="sd"> on the location, the ``title`` argument in the request is translated.</span>
+
+<span class="sd"> .. code:: python</span>
+
+<span class="sd"> &quot;custom&quot;: {</span>
+<span class="sd"> &quot;wiki_netloc&quot;: {</span>
+<span class="sd"> &quot;de&quot;: &quot;wiki.archlinux.de&quot;,</span>
+<span class="sd"> # ...</span>
+<span class="sd"> &quot;zh&quot;: &quot;wiki.archlinuxcn.org&quot;</span>
+<span class="sd"> }</span>
+<span class="sd"> &quot;title&quot;: {</span>
+<span class="sd"> &quot;de&quot;: &quot;Spezial:Suche&quot;,</span>
+<span class="sd"> # ...</span>
+<span class="sd"> &quot;zh&quot;: &quot;Special:\u641c\u7d22&quot;</span>
+<span class="sd"> },</span>
+<span class="sd"> },</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="n">title_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;de&#39;</span><span class="p">:</span> <span class="s1">&#39;Spezial:Suche&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fa&#39;</span><span class="p">:</span> <span class="s1">&#39;ویژه:جستجو&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ja&#39;</span><span class="p">:</span> <span class="s1">&#39;特別:検索&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;zh&#39;</span><span class="p">:</span> <span class="s1">&#39;Special:搜索&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://wiki.archlinux.org/&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from wiki.archlinux.org is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//a[@class=&#39;interlanguage-link-target&#39;]&quot;</span><span class="p">):</span>
+
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;lang&#39;</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">))</span>
+ <span class="c1"># zh_Hans --&gt; zh</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">sxng_tag</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+
+ <span class="n">netloc</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">netloc</span>
+ <span class="k">if</span> <span class="n">netloc</span> <span class="o">!=</span> <span class="s1">&#39;wiki.archlinux.org&#39;</span><span class="p">:</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">title_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">title</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: title tag from </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) is unknown&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">netloc</span><span class="p">,</span> <span class="n">sxng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">][</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">netloc</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">][</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">title</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="s2">&quot;.//span&quot;</span><span class="p">))</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="s1">&#39;en&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;English&#39;</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/bing.html b/_modules/searx/engines/bing.html
new file mode 100644
index 000000000..5f897597b
--- /dev/null
+++ b/_modules/searx/engines/bing.html
@@ -0,0 +1,391 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.bing &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.bing</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.bing</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Bing-WEB engine. Some of this</span>
+<span class="sd">implementations are shared by other engines:</span>
+
+<span class="sd">- :ref:`bing images engine`</span>
+<span class="sd">- :ref:`bing news engine`</span>
+<span class="sd">- :ref:`bing videos engine`</span>
+
+<span class="sd">On the `preference page`_ Bing offers a lot of languages an regions (see section</span>
+<span class="sd">LANGUAGE and COUNTRY/REGION). The Language is the language of the UI, we need</span>
+<span class="sd">in SearXNG to get the translations of data such as *&quot;published last week&quot;*.</span>
+
+<span class="sd">There is a description of the official search-APIs_, unfortunately this is not</span>
+<span class="sd">the API we can use or that bing itself would use. You can look up some things</span>
+<span class="sd">in the API to get a better picture of bing, but the value specifications like</span>
+<span class="sd">the market codes are usually outdated or at least no longer used by bing itself.</span>
+
+<span class="sd">The market codes have been harmonized and are identical for web, video and</span>
+<span class="sd">images. The news area has also been harmonized with the other categories. Only</span>
+<span class="sd">political adjustments still seem to be made -- for example, there is no news</span>
+<span class="sd">category for the Chinese market.</span>
+
+<span class="sd">.. _preference page: https://www.bing.com/account/general</span>
+<span class="sd">.. _search-APIs: https://learn.microsoft.com/en-us/bing/search-apis/</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="c1"># pylint: disable=too-many-branches, invalid-name</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">import</span> <span class="nn">base64</span>
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">import</span> <span class="nn">time</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">parse_qs</span><span class="p">,</span> <span class="n">urlencode</span><span class="p">,</span> <span class="n">urlparse</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+<span class="kn">import</span> <span class="nn">babel.languages</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">,</span> <span class="n">eval_xpath_getindex</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span><span class="p">,</span> <span class="n">region_tag</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.bing.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q182496&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.microsoft.com/en-us/bing/apis/bing-web-search-api&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">200</span>
+<span class="sd">&quot;&quot;&quot;200 pages maximum (``&amp;first=1991``)&quot;&quot;&quot;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="sd">&quot;&quot;&quot;Bing results are always SFW. To get NSFW links from bing some age</span>
+<span class="sd">verification by a cookie is needed / thats not possible in SearXNG.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.bing.com/search&#39;</span>
+<span class="sd">&quot;&quot;&quot;Bing (Web) search URL&quot;&quot;&quot;</span>
+
+
+<span class="k">def</span> <span class="nf">_page_offset</span><span class="p">(</span><span class="n">pageno</span><span class="p">):</span>
+ <span class="k">return</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">pageno</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="mi">1</span>
+
+
+<span class="k">def</span> <span class="nf">set_bing_cookies</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">engine_language</span><span class="p">,</span> <span class="n">engine_region</span><span class="p">):</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;_EDGE_CD&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;m=</span><span class="si">{</span><span class="n">engine_region</span><span class="si">}</span><span class="s1">&amp;u=</span><span class="si">{</span><span class="n">engine_language</span><span class="si">}</span><span class="s1">&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;_EDGE_S&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;mkt=</span><span class="si">{</span><span class="n">engine_region</span><span class="si">}</span><span class="s1">&amp;ui=</span><span class="si">{</span><span class="n">engine_language</span><span class="si">}</span><span class="s1">&#39;</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;bing cookies: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">])</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a Bing-Web request.&quot;&quot;&quot;</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">engine_language</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">set_bing_cookies</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">engine_language</span><span class="p">,</span> <span class="n">engine_region</span><span class="p">)</span>
+
+ <span class="n">page</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="c1"># if arg &#39;pq&#39; is missed, sometimes on page 4 we get results from page 1,</span>
+ <span class="c1"># don&#39;t ask why it is only sometimes / its M$ and they have never been</span>
+ <span class="c1"># deterministic ;)</span>
+ <span class="s1">&#39;pq&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="c1"># To get correct page, arg first and this arg FORM is needed, the value PERE</span>
+ <span class="c1"># is on page 2, on page 3 its PERE1 and on page 4 its PERE2 .. and so forth.</span>
+ <span class="c1"># The &#39;first&#39; arg should never send on page 1.</span>
+
+ <span class="k">if</span> <span class="n">page</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;first&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_page_offset</span><span class="p">(</span><span class="n">page</span><span class="p">)</span> <span class="c1"># see also arg FORM</span>
+ <span class="k">if</span> <span class="n">page</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;FORM&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;PERE&#39;</span>
+ <span class="k">elif</span> <span class="n">page</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;FORM&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;PERE</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">page</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s1">?</span><span class="si">{</span><span class="n">urlencode</span><span class="p">(</span><span class="n">query_params</span><span class="p">)</span><span class="si">}</span><span class="s1">&#39;</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;time_range&#39;</span><span class="p">):</span>
+ <span class="n">unix_day</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">()</span> <span class="o">/</span> <span class="mi">86400</span><span class="p">)</span>
+ <span class="n">time_ranges</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;2&#39;</span><span class="p">,</span> <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;3&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="sa">f</span><span class="s1">&#39;5_</span><span class="si">{</span><span class="n">unix_day</span><span class="o">-</span><span class="mi">365</span><span class="si">}</span><span class="s1">_</span><span class="si">{</span><span class="n">unix_day</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">}</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="sa">f</span><span class="s1">&#39;&amp;filters=ex1:&quot;ez</span><span class="si">{</span><span class="n">time_ranges</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;time_range&quot;</span><span class="p">]]</span><span class="si">}</span><span class="s1">&quot;&#39;</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="c1"># pylint: disable=too-many-locals</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">result_len</span> <span class="o">=</span> <span class="mi">0</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="c1"># parse results again if nothing is found yet</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//ol[@id=&quot;b_results&quot;]/li[contains(@class, &quot;b_algo&quot;)]&#39;</span><span class="p">):</span>
+
+ <span class="n">link</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//h2/a&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">link</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">attrib</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">)</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">link</span><span class="p">)</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//p&#39;</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">content</span><span class="p">:</span>
+ <span class="c1"># Make sure that the element is free of:</span>
+ <span class="c1"># &lt;span class=&quot;algoSlug_icon&quot; # data-priority=&quot;2&quot;&gt;Web&lt;/span&gt;</span>
+ <span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">p</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//span[@class=&quot;algoSlug_icon&quot;]&#39;</span><span class="p">):</span>
+ <span class="n">e</span><span class="o">.</span><span class="n">getparent</span><span class="p">()</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
+
+ <span class="c1"># get the real URL</span>
+ <span class="k">if</span> <span class="n">url</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;https://www.bing.com/ck/a?&#39;</span><span class="p">):</span>
+ <span class="c1"># get the first value of u parameter</span>
+ <span class="n">url_query</span> <span class="o">=</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">query</span>
+ <span class="n">parsed_url_query</span> <span class="o">=</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">url_query</span><span class="p">)</span>
+ <span class="n">param_u</span> <span class="o">=</span> <span class="n">parsed_url_query</span><span class="p">[</span><span class="s2">&quot;u&quot;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
+ <span class="c1"># remove &quot;a1&quot; in front</span>
+ <span class="n">encoded_url</span> <span class="o">=</span> <span class="n">param_u</span><span class="p">[</span><span class="mi">2</span><span class="p">:]</span>
+ <span class="c1"># add padding</span>
+ <span class="n">encoded_url</span> <span class="o">=</span> <span class="n">encoded_url</span> <span class="o">+</span> <span class="s1">&#39;=&#39;</span> <span class="o">*</span> <span class="p">(</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="n">encoded_url</span><span class="p">)</span> <span class="o">%</span> <span class="mi">4</span><span class="p">)</span>
+ <span class="c1"># decode base64 encoded URL</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">urlsafe_b64decode</span><span class="p">(</span><span class="n">encoded_url</span><span class="p">)</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+
+ <span class="c1"># append result</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">})</span>
+
+ <span class="c1"># get number_of_results</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">result_len_container</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//span[@class=&quot;sb_count&quot;]//text()&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="s2">&quot;-&quot;</span> <span class="ow">in</span> <span class="n">result_len_container</span><span class="p">:</span>
+
+ <span class="c1"># Remove the part &quot;from-to&quot; for paginated request ...</span>
+ <span class="n">result_len_container</span> <span class="o">=</span> <span class="n">result_len_container</span><span class="p">[</span><span class="n">result_len_container</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">&quot;-&quot;</span><span class="p">)</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">+</span> <span class="mi">2</span> <span class="p">:]</span>
+
+ <span class="n">result_len_container</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="s1">&#39;[^0-9]&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="n">result_len_container</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">result_len_container</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">result_len</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">result_len_container</span><span class="p">)</span>
+
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> <span class="c1"># pylint: disable=broad-except</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;result error :</span><span class="se">\n</span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">result_len</span> <span class="ow">and</span> <span class="n">_page_offset</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;pageno&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span> <span class="o">&gt;</span> <span class="n">result_len</span><span class="p">:</span>
+ <span class="c1"># Avoid reading more results than available.</span>
+ <span class="c1"># For example, if there is 100 results from some search and we try to get results from 120 to 130,</span>
+ <span class="c1"># Bing will send back the results from 0 to 10 and no error.</span>
+ <span class="c1"># If we compare results count with the first parameter of the request we can avoid this &quot;invalid&quot; results.</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;number_of_results&#39;</span><span class="p">:</span> <span class="n">result_len</span><span class="p">})</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and regions from Bing-Web.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+ <span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">gen_useragent</span>
+
+ <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;User-Agent&quot;</span><span class="p">:</span> <span class="n">gen_useragent</span><span class="p">(),</span>
+ <span class="s2">&quot;Accept&quot;</span><span class="p">:</span> <span class="s2">&quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Accept-Language&quot;</span><span class="p">:</span> <span class="s2">&quot;en-US;q=0.5,en;q=0.3&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Accept-Encoding&quot;</span><span class="p">:</span> <span class="s2">&quot;gzip, deflate, br&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;DNT&quot;</span><span class="p">:</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Connection&quot;</span><span class="p">:</span> <span class="s2">&quot;keep-alive&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Upgrade-Insecure-Requests&quot;</span><span class="p">:</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Sec-GPC&quot;</span><span class="p">:</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;Cache-Control&quot;</span><span class="p">:</span> <span class="s2">&quot;max-age=0&quot;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s2">&quot;https://www.bing.com/account/general&quot;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from bing is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="c1"># languages</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="s1">&#39;zh&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;zh-hans&#39;</span>
+
+ <span class="n">map_lang</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;prs&#39;</span><span class="p">:</span> <span class="s1">&#39;fa-AF&#39;</span><span class="p">,</span> <span class="s1">&#39;en&#39;</span><span class="p">:</span> <span class="s1">&#39;en-us&#39;</span><span class="p">}</span>
+ <span class="n">bing_ui_lang_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="c1"># HINT: this list probably needs to be supplemented</span>
+ <span class="s1">&#39;en&#39;</span><span class="p">:</span> <span class="s1">&#39;us&#39;</span><span class="p">,</span> <span class="c1"># en --&gt; en-us</span>
+ <span class="s1">&#39;da&#39;</span><span class="p">:</span> <span class="s1">&#39;dk&#39;</span><span class="p">,</span> <span class="c1"># da --&gt; da-dk</span>
+ <span class="p">}</span>
+
+ <span class="k">for</span> <span class="n">href</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@id=&quot;language-section&quot;]//li/a/@href&#39;</span><span class="p">):</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">urlparse</span><span class="p">(</span><span class="n">href</span><span class="p">)</span><span class="o">.</span><span class="n">query</span><span class="p">)[</span><span class="s1">&#39;setlang&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">babel_lang</span> <span class="o">=</span> <span class="n">map_lang</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_lang</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">)</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">babel_lang</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;_&#39;</span><span class="p">)))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: language (</span><span class="si">%s</span><span class="s2">) is unknown by babel&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">babel_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="c1"># Language (e.g. &#39;en&#39; or &#39;de&#39;) from https://www.bing.com/account/general</span>
+ <span class="c1"># is converted by bing to &#39;en-us&#39; or &#39;de-de&#39;. But only if there is not</span>
+ <span class="c1"># already a &#39;-&#39; delemitter in the language. For instance &#39;pt-PT&#39; --&gt;</span>
+ <span class="c1"># &#39;pt-pt&#39; and &#39;pt-br&#39; --&gt; &#39;pt-br&#39;</span>
+ <span class="n">bing_ui_lang</span> <span class="o">=</span> <span class="n">eng_lang</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
+ <span class="k">if</span> <span class="s1">&#39;-&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">bing_ui_lang</span><span class="p">:</span>
+ <span class="n">bing_ui_lang</span> <span class="o">=</span> <span class="n">bing_ui_lang</span> <span class="o">+</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">bing_ui_lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">bing_ui_lang</span><span class="p">,</span> <span class="n">bing_ui_lang</span><span class="p">)</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">bing_ui_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">{</span><span class="n">sxng_tag</span><span class="si">}</span><span class="s2"> --&gt; </span><span class="si">{</span><span class="n">conflict</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">bing_ui_lang</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">bing_ui_lang</span>
+
+ <span class="c1"># regions (aka &quot;market codes&quot;)</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="s1">&#39;zh-CN&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;zh-cn&#39;</span>
+
+ <span class="n">map_market_codes</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;zh-hk&#39;</span><span class="p">:</span> <span class="s1">&#39;en-hk&#39;</span><span class="p">,</span> <span class="c1"># not sure why, but at M$ this is the market code for Hongkong</span>
+ <span class="p">}</span>
+ <span class="k">for</span> <span class="n">href</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@id=&quot;region-section&quot;]//li/a/@href&#39;</span><span class="p">):</span>
+ <span class="n">cc_tag</span> <span class="o">=</span> <span class="n">parse_qs</span><span class="p">(</span><span class="n">urlparse</span><span class="p">(</span><span class="n">href</span><span class="p">)</span><span class="o">.</span><span class="n">query</span><span class="p">)[</span><span class="s1">&#39;cc&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">cc_tag</span> <span class="o">==</span> <span class="s1">&#39;clear&#39;</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="n">cc_tag</span>
+ <span class="k">continue</span>
+
+ <span class="c1"># add market codes from official languages of the country ..</span>
+ <span class="k">for</span> <span class="n">lang_tag</span> <span class="ow">in</span> <span class="n">babel</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get_official_languages</span><span class="p">(</span><span class="n">cc_tag</span><span class="p">,</span> <span class="n">de_facto</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">lang_tag</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
+ <span class="c1"># print(&quot;ignore lang: %s &lt;-- %s&quot; % (cc_tag, lang_tag))</span>
+ <span class="k">continue</span>
+ <span class="n">lang_tag</span> <span class="o">=</span> <span class="n">lang_tag</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># zh_Hant --&gt; zh</span>
+ <span class="n">market_code</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">lang_tag</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="n">cc_tag</span><span class="si">}</span><span class="s2">&quot;</span> <span class="c1"># zh-tw</span>
+
+ <span class="n">market_code</span> <span class="o">=</span> <span class="n">map_market_codes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">market_code</span><span class="p">,</span> <span class="n">market_code</span><span class="p">)</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">_</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">lang_tag</span><span class="p">,</span> <span class="n">cc_tag</span><span class="o">.</span><span class="n">upper</span><span class="p">())))</span>
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">market_code</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">market_code</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">market_code</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/bing_images.html b/_modules/searx/engines/bing_images.html
new file mode 100644
index 000000000..a43a571d5
--- /dev/null
+++ b/_modules/searx/engines/bing_images.html
@@ -0,0 +1,223 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.bing_images &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.bing_images</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.bing_images</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Bing-Images: description see :py:obj:`searx.engines.bing`.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="c1"># pylint: disable=invalid-name</span>
+
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">import</span> <span class="nn">json</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">set_bing_cookies</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.bing.com/images&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q182496&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.microsoft.com/en-us/bing/apis/bing-image-search-api&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;images&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.bing.com/images/async&#39;</span>
+<span class="sd">&quot;&quot;&quot;Bing (Images) search URL&quot;&quot;&quot;</span>
+
+<span class="n">time_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">24</span><span class="p">,</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">7</span><span class="p">,</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">31</span><span class="p">,</span>
+ <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">365</span><span class="p">,</span>
+<span class="p">}</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_images.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a Bing-Image request.&quot;&quot;&quot;</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">engine_language</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">set_bing_cookies</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">engine_language</span><span class="p">,</span> <span class="n">engine_region</span><span class="p">)</span>
+
+ <span class="c1"># build URL query</span>
+ <span class="c1"># - example: https://www.bing.com/images/async?q=foo&amp;async=content&amp;first=1&amp;count=35</span>
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;async&#39;</span><span class="p">:</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span>
+ <span class="c1"># to simplify the page count lets use the default of 35 images per page</span>
+ <span class="s1">&#39;first&#39;</span><span class="p">:</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">35</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="s1">&#39;count&#39;</span><span class="p">:</span> <span class="mi">35</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="c1"># time range</span>
+ <span class="c1"># - example: one year (525600 minutes) &#39;qft=+filterui:age-lt525600&#39;</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;qft&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;filterui:age-lt</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">time_map</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;?&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">query_params</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_images.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from Bing-Images&quot;&quot;&quot;</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//ul[contains(@class, &quot;dgControl_list&quot;)]/li&#39;</span><span class="p">):</span>
+
+ <span class="n">metadata</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//a[@class=&quot;iusc&quot;]/@m&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">metadata</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="n">metadata</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//a[@class=&quot;iusc&quot;]/@m&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;infnmpt&quot;]//a/text()&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="n">img_format</span> <span class="o">=</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;imgpt&quot;]/div/span/text()&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot; · &quot;</span><span class="p">)</span>
+ <span class="n">source</span> <span class="o">=</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;imgpt&quot;]//div[@class=&quot;lnkw&quot;]//a/text()&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="p">[</span><span class="s1">&#39;purl&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail_src&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="p">[</span><span class="s1">&#39;turl&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="p">[</span><span class="s1">&#39;murl&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;desc&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;source&#39;</span><span class="p">:</span> <span class="n">source</span><span class="p">,</span>
+ <span class="s1">&#39;resolution&#39;</span><span class="p">:</span> <span class="n">img_format</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
+ <span class="s1">&#39;img_format&#39;</span><span class="p">:</span> <span class="n">img_format</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">img_format</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">2</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/bing_news.html b/_modules/searx/engines/bing_news.html
new file mode 100644
index 000000000..56aca9c2e
--- /dev/null
+++ b/_modules/searx/engines/bing_news.html
@@ -0,0 +1,277 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.bing_news &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.bing_news</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.bing_news</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Bing-News: description see :py:obj:`searx.engines.bing`.</span>
+
+<span class="sd">.. hint::</span>
+
+<span class="sd"> Bing News is *different* in some ways!</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="c1"># pylint: disable=invalid-name</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">,</span> <span class="n">eval_xpath_getindex</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">set_bing_cookies</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.bing.com/news&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q2878637&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.microsoft.com/en-us/bing/apis/bing-news-search-api&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;RSS&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;news&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="sd">&quot;&quot;&quot;If go through the pages and there are actually no new results for another</span>
+<span class="sd">page, then bing returns the results from the last page again.&quot;&quot;&quot;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;interval=&quot;4&quot;&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;interval=&quot;7&quot;&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;interval=&quot;9&quot;&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="sd">&quot;&quot;&quot;A string &#39;4&#39; means *last hour*. We use *last hour* for ``day`` here since the</span>
+<span class="sd">difference of *last day* and *last week* in the result list is just marginally.</span>
+<span class="sd">Bing does not have news range ``year`` / we use ``month`` instead.&quot;&quot;&quot;</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.bing.com/news/infinitescrollajax&#39;</span>
+<span class="sd">&quot;&quot;&quot;Bing (News) search URL&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_news.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a Bing-News request.&quot;&quot;&quot;</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">engine_language</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">set_bing_cookies</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">engine_language</span><span class="p">,</span> <span class="n">engine_region</span><span class="p">)</span>
+
+ <span class="c1"># build URL query</span>
+ <span class="c1">#</span>
+ <span class="c1"># example: https://www.bing.com/news/infinitescrollajax?q=london&amp;first=1</span>
+
+ <span class="n">page</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">-</span> <span class="mi">1</span>
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;InfiniteScroll&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="c1"># to simplify the page count lets use the default of 10 images per page</span>
+ <span class="s1">&#39;first&#39;</span><span class="p">:</span> <span class="n">page</span> <span class="o">*</span> <span class="mi">10</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="s1">&#39;SFX&#39;</span><span class="p">:</span> <span class="n">page</span><span class="p">,</span>
+ <span class="s1">&#39;form&#39;</span><span class="p">:</span> <span class="s1">&#39;PTFTNR&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;setlang&#39;</span><span class="p">:</span> <span class="n">engine_region</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span>
+ <span class="s1">&#39;cc&#39;</span><span class="p">:</span> <span class="n">engine_region</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span>
+ <span class="p">}</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;qft&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">],</span> <span class="s1">&#39;interval=&quot;9&quot;&#39;</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;?&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">query_params</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_news.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from Bing-Video&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">newsitem</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;newsitem&quot;)]&#39;</span><span class="p">):</span>
+
+ <span class="n">link</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">newsitem</span><span class="p">,</span> <span class="s1">&#39;.//a[@class=&quot;title&quot;]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">link</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">attrib</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">)</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">link</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">newsitem</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;snippet&quot;]&#39;</span><span class="p">))</span>
+
+ <span class="n">metadata</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">source</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">newsitem</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;source&quot;)]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">source</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="p">(</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">source</span><span class="p">,</span> <span class="s1">&#39;.//span[@aria-label]/@aria-label&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">),</span>
+ <span class="c1"># eval_xpath_getindex(source, &#39;.//a&#39;, 0, None),</span>
+ <span class="c1"># eval_xpath_getindex(source, &#39;./div/span&#39;, 3, None),</span>
+ <span class="n">link</span><span class="o">.</span><span class="n">attrib</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;data-author&#39;</span><span class="p">),</span>
+ <span class="p">):</span>
+ <span class="k">if</span> <span class="n">item</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">t</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">t</span> <span class="ow">and</span> <span class="n">t</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
+ <span class="n">metadata</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">t</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
+ <span class="n">metadata</span> <span class="o">=</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">metadata</span><span class="p">)</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">imagelink</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">newsitem</span><span class="p">,</span> <span class="s1">&#39;.//a[@class=&quot;imagelink&quot;]//img&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">imagelink</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">imagelink</span><span class="o">.</span><span class="n">attrib</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;src&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">thumbnail</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;https://www.bing.com&quot;</span><span class="p">):</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="s1">&#39;https://www.bing.com/&#39;</span> <span class="o">+</span> <span class="n">thumbnail</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="s1">&#39;metadata&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_news.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and regions from Bing-News.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+
+ <span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="k">as</span> <span class="n">_f</span>
+
+ <span class="n">_f</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">)</span>
+
+ <span class="c1"># fix market codes not known by bing news:</span>
+
+ <span class="c1"># In bing the market code &#39;zh-cn&#39; exists, but there is no &#39;news&#39; category in</span>
+ <span class="c1"># bing for this market. Alternatively we use the the market code from Honk</span>
+ <span class="c1"># Kong. Even if this is not correct, it is better than having no hits at</span>
+ <span class="c1"># all, or sending false queries to bing that could raise the suspicion of a</span>
+ <span class="c1"># bot.</span>
+
+ <span class="c1"># HINT: &#39;en-hk&#39; is the region code it does not indicate the language en!!</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="s1">&#39;zh-CN&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;en-hk&#39;</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/bing_videos.html b/_modules/searx/engines/bing_videos.html
new file mode 100644
index 000000000..85683d0c9
--- /dev/null
+++ b/_modules/searx/engines/bing_videos.html
@@ -0,0 +1,212 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.bing_videos &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.bing_videos</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.bing_videos</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="c1"># pylint: disable=invalid-name</span>
+<span class="sd">&quot;&quot;&quot;Bing-Videos: description see :py:obj:`searx.engines.bing`.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">import</span> <span class="nn">json</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">set_bing_cookies</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.bing_images</span> <span class="kn">import</span> <span class="n">time_map</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.bing.com/videos&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q4914152&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.microsoft.com/en-us/bing/apis/bing-video-search-api&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;videos&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.bing.com/videos/asyncv2&#39;</span>
+<span class="sd">&quot;&quot;&quot;Bing (Videos) async search URL.&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_videos.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a Bing-Video request.&quot;&quot;&quot;</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">engine_language</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">set_bing_cookies</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">engine_language</span><span class="p">,</span> <span class="n">engine_region</span><span class="p">)</span>
+
+ <span class="c1"># build URL query</span>
+ <span class="c1">#</span>
+ <span class="c1"># example: https://www.bing.com/videos/asyncv2?q=foo&amp;async=content&amp;first=1&amp;count=35</span>
+
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;async&#39;</span><span class="p">:</span> <span class="s1">&#39;content&#39;</span><span class="p">,</span>
+ <span class="c1"># to simplify the page count lets use the default of 35 images per page</span>
+ <span class="s1">&#39;first&#39;</span><span class="p">:</span> <span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">35</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="s1">&#39;count&#39;</span><span class="p">:</span> <span class="mi">35</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="c1"># time range</span>
+ <span class="c1">#</span>
+ <span class="c1"># example: one week (10080 minutes) &#39;&amp;qft= filterui:videoage-lt10080&#39; &#39;&amp;form=VRFLTR&#39;</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;form&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;VRFLTR&#39;</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;qft&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39; filterui:videoage-lt</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">time_map</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;?&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">query_params</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/bing.html#searx.engines.bing_videos.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from Bing-Video&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//div[@class=&quot;dg_u&quot;]//div[contains(@id, &quot;mc_vtvc_video&quot;)]&#39;</span><span class="p">):</span>
+ <span class="n">metadata</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;vrhdata&quot;]/@vrhm&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
+ <span class="n">info</span> <span class="o">=</span> <span class="s1">&#39; - &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[@class=&quot;mc_vtvc_meta_block&quot;]//span/text()&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="si">{0}</span><span class="s1"> - </span><span class="si">{1}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">metadata</span><span class="p">[</span><span class="s1">&#39;du&#39;</span><span class="p">],</span> <span class="n">info</span><span class="p">)</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//div[contains(@class, &quot;mc_vtvc_th&quot;)]//img/@src&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="p">[</span><span class="s1">&#39;murl&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">metadata</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;vt&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/brave.html b/_modules/searx/engines/brave.html
new file mode 100644
index 000000000..aa271f721
--- /dev/null
+++ b/_modules/searx/engines/brave.html
@@ -0,0 +1,580 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.brave &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.brave</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.brave</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Brave supports the categories listed in :py:obj:`brave_category` (General,</span>
+<span class="sd">news, videos, images). The support of :py:obj:`paging` and :py:obj:`time range</span>
+<span class="sd">&lt;time_range_support&gt;` is limited (see remarks).</span>
+
+<span class="sd">Configured ``brave`` engines:</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: brave</span>
+<span class="sd"> engine: brave</span>
+<span class="sd"> ...</span>
+<span class="sd"> brave_category: search</span>
+<span class="sd"> time_range_support: true</span>
+<span class="sd"> paging: true</span>
+
+<span class="sd"> - name: brave.images</span>
+<span class="sd"> engine: brave</span>
+<span class="sd"> ...</span>
+<span class="sd"> brave_category: images</span>
+
+<span class="sd"> - name: brave.videos</span>
+<span class="sd"> engine: brave</span>
+<span class="sd"> ...</span>
+<span class="sd"> brave_category: videos</span>
+
+<span class="sd"> - name: brave.news</span>
+<span class="sd"> engine: brave</span>
+<span class="sd"> ...</span>
+<span class="sd"> brave_category: news</span>
+
+<span class="sd"> - name: brave.goggles</span>
+<span class="sd"> brave_category: goggles</span>
+<span class="sd"> time_range_support: true</span>
+<span class="sd"> paging: true</span>
+<span class="sd"> ...</span>
+<span class="sd"> brave_category: goggles</span>
+
+
+<span class="sd">.. _brave regions:</span>
+
+<span class="sd">Brave regions</span>
+<span class="sd">=============</span>
+
+<span class="sd">Brave uses two-digit tags for the regions like ``ca`` while SearXNG deals with</span>
+<span class="sd">locales. To get a mapping, all *officiat de-facto* languages of the Brave</span>
+<span class="sd">region are mapped to regions in SearXNG (see :py:obj:`babel</span>
+<span class="sd">&lt;babel.languages.get_official_languages&gt;`):</span>
+
+<span class="sd">.. code:: python</span>
+
+<span class="sd"> &quot;regions&quot;: {</span>
+<span class="sd"> ..</span>
+<span class="sd"> &quot;en-CA&quot;: &quot;ca&quot;,</span>
+<span class="sd"> &quot;fr-CA&quot;: &quot;ca&quot;,</span>
+<span class="sd"> ..</span>
+<span class="sd"> }</span>
+
+
+<span class="sd">.. note::</span>
+
+<span class="sd"> The language (aka region) support of Brave&#39;s index is limited to very basic</span>
+<span class="sd"> languages. The search results for languages like Chinese or Arabic are of</span>
+<span class="sd"> low quality.</span>
+
+
+<span class="sd">.. _brave googles:</span>
+
+<span class="sd">Brave Goggles</span>
+<span class="sd">=============</span>
+
+<span class="sd">.. _list of Goggles: https://search.brave.com/goggles/discover</span>
+<span class="sd">.. _Goggles Whitepaper: https://brave.com/static-assets/files/goggles.pdf</span>
+<span class="sd">.. _Goggles Quickstart: https://github.com/brave/goggles-quickstart</span>
+
+<span class="sd">Goggles allow you to choose, alter, or extend the ranking of Brave Search</span>
+<span class="sd">results (`Goggles Whitepaper`_). Goggles are openly developed by the community</span>
+<span class="sd">of Brave Search users.</span>
+
+<span class="sd">Select from the `list of Goggles`_ people have published, or create your own</span>
+<span class="sd">(`Goggles Quickstart`_).</span>
+
+
+<span class="sd">.. _brave languages:</span>
+
+<span class="sd">Brave languages</span>
+<span class="sd">===============</span>
+
+<span class="sd">Brave&#39;s language support is limited to the UI (menus, area local notations,</span>
+<span class="sd">etc). Brave&#39;s index only seems to support a locale, but it does not seem to</span>
+<span class="sd">support any languages in its index. The choice of available languages is very</span>
+<span class="sd">small (and its not clear to me where the difference in UI is when switching</span>
+<span class="sd">from en-us to en-ca or en-gb).</span>
+
+<span class="sd">In the :py:obj:`EngineTraits object &lt;searx.enginelib.traits.EngineTraits&gt;` the</span>
+<span class="sd">UI languages are stored in a custom field named ``ui_lang``:</span>
+
+<span class="sd">.. code:: python</span>
+
+<span class="sd"> &quot;custom&quot;: {</span>
+<span class="sd"> &quot;ui_lang&quot;: {</span>
+<span class="sd"> &quot;ca&quot;: &quot;ca&quot;,</span>
+<span class="sd"> &quot;de-DE&quot;: &quot;de-de&quot;,</span>
+<span class="sd"> &quot;en-CA&quot;: &quot;en-ca&quot;,</span>
+<span class="sd"> &quot;en-GB&quot;: &quot;en-gb&quot;,</span>
+<span class="sd"> &quot;en-US&quot;: &quot;en-us&quot;,</span>
+<span class="sd"> &quot;es&quot;: &quot;es&quot;,</span>
+<span class="sd"> &quot;fr-CA&quot;: &quot;fr-ca&quot;,</span>
+<span class="sd"> &quot;fr-FR&quot;: &quot;fr-fr&quot;,</span>
+<span class="sd"> &quot;ja-JP&quot;: &quot;ja-jp&quot;,</span>
+<span class="sd"> &quot;pt-BR&quot;: &quot;pt-br&quot;,</span>
+<span class="sd"> &quot;sq-AL&quot;: &quot;sq-al&quot;</span>
+<span class="sd"> }</span>
+<span class="sd"> },</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">urlencode</span><span class="p">,</span>
+ <span class="n">urlparse</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="kn">from</span> <span class="nn">dateutil</span> <span class="kn">import</span> <span class="n">parser</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">locales</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+ <span class="n">extr</span><span class="p">,</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">,</span>
+ <span class="n">js_variable_to_python</span><span class="p">,</span>
+ <span class="n">get_embeded_stream_url</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://search.brave.com/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q22906900&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;https://search.brave.com/&quot;</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">brave_category</span> <span class="o">=</span> <span class="s1">&#39;search&#39;</span>
+<span class="n">Goggles</span> <span class="o">=</span> <span class="n">Any</span>
+<span class="sd">&quot;&quot;&quot;Brave supports common web-search, videos, images, news, and goggles search.</span>
+
+<span class="sd">- ``search``: Common WEB search</span>
+<span class="sd">- ``videos``: search for videos</span>
+<span class="sd">- ``images``: search for images</span>
+<span class="sd">- ``news``: search for news</span>
+<span class="sd">- ``goggles``: Common WEB search with custom rules</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">brave_spellcheck</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&quot;&quot;&quot;Brave supports some kind of spell checking. When activated, Brave tries to</span>
+<span class="sd">fix typos, e.g. it searches for ``food`` when the user queries for ``fooh``. In</span>
+<span class="sd">the UI of Brave the user gets warned about this, since we can not warn the user</span>
+<span class="sd">in SearXNG, the spellchecking is disabled by default.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&quot;&quot;&quot;Brave only supports paging in :py:obj:`brave_category` ``search`` (UI</span>
+<span class="sd">category All) and in the goggles category.&quot;&quot;&quot;</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">10</span>
+<span class="sd">&quot;&quot;&quot;Tested 9 pages maximum (``&amp;offset=8``), to be save max is set to 10. Trying</span>
+<span class="sd">to do more won&#39;t return any result and you will most likely be flagged as a bot.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch_map</span> <span class="o">=</span> <span class="p">{</span><span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;strict&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;moderate&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;off&#39;</span><span class="p">}</span> <span class="c1"># cookie: safesearch=off</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&quot;&quot;&quot;Brave only supports time-range in :py:obj:`brave_category` ``search`` (UI</span>
+<span class="sd">category All) and in the goggles category.&quot;&quot;&quot;</span>
+
+<span class="n">time_range_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;pd&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;pw&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;pm&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="s1">&#39;py&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="c1"># Don&#39;t accept br encoding / see https://github.com/searxng/searxng/pull/1787</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Accept-Encoding&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;gzip, deflate&#39;</span>
+
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="k">if</span> <span class="n">brave_spellcheck</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;spellcheck&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;search&#39;</span><span class="p">,</span> <span class="s1">&#39;goggles&#39;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;offset&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pageno&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="mi">1</span>
+ <span class="k">if</span> <span class="n">time_range_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]):</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;tf&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_range_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">])</span>
+
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="o">==</span> <span class="s1">&#39;goggles&#39;</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;goggles_id&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">Goggles</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}{</span><span class="n">brave_category</span><span class="si">}</span><span class="s2">?</span><span class="si">{</span><span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
+
+ <span class="c1"># set properties in the cookies</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">safesearch_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">],</span> <span class="s1">&#39;off&#39;</span><span class="p">)</span>
+ <span class="c1"># the useLocation is IP based, we use cookie &#39;country&#39; for the region</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;useLocation&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;0&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;summarizer&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;0&#39;</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;all&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;country&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_region</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">ui_lang</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">get_engine_locale</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ui_lang&quot;</span><span class="p">],</span> <span class="s1">&#39;en-us&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;ui_lang&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ui_lang</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;cookies </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">])</span>
+
+
+<span class="k">def</span> <span class="nf">_extract_published_date</span><span class="p">(</span><span class="n">published_date_raw</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">published_date_raw</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">published_date_raw</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">parser</span><span class="o">.</span><span class="n">ParserError</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;search&#39;</span><span class="p">,</span> <span class="s1">&#39;goggles&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">_parse_search</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="n">datastr</span> <span class="o">=</span> <span class="n">extr</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="s2">&quot;const data = &quot;</span><span class="p">,</span> <span class="s2">&quot;;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">js_variable_to_python</span><span class="p">(</span><span class="n">datastr</span><span class="p">)</span>
+ <span class="n">json_resp</span> <span class="o">=</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;body&#39;</span><span class="p">][</span><span class="s1">&#39;response&#39;</span><span class="p">]</span>
+
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="o">==</span> <span class="s1">&#39;news&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">_parse_news</span><span class="p">(</span><span class="n">json_resp</span><span class="p">[</span><span class="s1">&#39;news&#39;</span><span class="p">])</span>
+
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="o">==</span> <span class="s1">&#39;images&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">_parse_images</span><span class="p">(</span><span class="n">json_resp</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">brave_category</span> <span class="o">==</span> <span class="s1">&#39;videos&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">_parse_videos</span><span class="p">(</span><span class="n">json_resp</span><span class="p">)</span>
+
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Unsupported brave category: </span><span class="si">{</span><span class="n">brave_category</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_search</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="n">result_list</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="n">answer_tag</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@class=&quot;answer&quot;]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">answer_tag</span><span class="p">:</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@id=&quot;featured_snippet&quot;]/a[@class=&quot;result-header&quot;]/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="n">result_list</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;answer&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">answer_tag</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">})</span>
+
+ <span class="c1"># xpath_results = &#39;//div[contains(@class, &quot;snippet fdb&quot;) and @data-type=&quot;web&quot;]&#39;</span>
+ <span class="n">xpath_results</span> <span class="o">=</span> <span class="s1">&#39;//div[contains(@class, &quot;snippet &quot;)]&#39;</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">xpath_results</span><span class="p">):</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a[contains(@class, &quot;h&quot;)]/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="n">title_tag</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span>
+ <span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a[contains(@class, &quot;h&quot;)]//div[contains(@class, &quot;title&quot;)]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span>
+ <span class="p">)</span>
+ <span class="k">if</span> <span class="n">url</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">title_tag</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">netloc</span><span class="p">:</span> <span class="c1"># partial url likely means it&#39;s an ad</span>
+ <span class="k">continue</span>
+
+ <span class="n">content_tag</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;snippet-description&quot;)]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">pub_date_raw</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;substring-before(.//div[contains(@class, &quot;snippet-description&quot;)], &quot;-&quot;)&#39;</span><span class="p">)</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//img[contains(@class, &quot;thumb&quot;)]/@src&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">title_tag</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">content_tag</span><span class="p">),</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">_extract_published_date</span><span class="p">(</span><span class="n">pub_date_raw</span><span class="p">),</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">video_tag</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span>
+ <span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;video-snippet&quot;) and @data-macro=&quot;video&quot;]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span>
+ <span class="p">)</span>
+ <span class="k">if</span> <span class="n">video_tag</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+
+ <span class="c1"># In my tests a video tag in the WEB search was most often not a</span>
+ <span class="c1"># video, except the ones from youtube ..</span>
+
+ <span class="n">iframe_src</span> <span class="o">=</span> <span class="n">get_embeded_stream_url</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">iframe_src</span><span class="p">:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;iframe_src&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">iframe_src</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;template&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;videos.html&#39;</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">video_tag</span><span class="p">,</span> <span class="s1">&#39;.//img/@src&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">pub_date_raw</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">(</span><span class="n">video_tag</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;snippet-attributes&quot;)]/div/text()&#39;</span><span class="p">)</span>
+ <span class="p">)</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;publishedDate&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_extract_published_date</span><span class="p">(</span><span class="n">pub_date_raw</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">video_tag</span><span class="p">,</span> <span class="s1">&#39;.//img/@src&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+
+ <span class="n">result_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">result_list</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_news</span><span class="p">(</span><span class="n">json_resp</span><span class="p">):</span>
+ <span class="n">result_list</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_resp</span><span class="p">[</span><span class="s2">&quot;results&quot;</span><span class="p">]:</span>
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">_extract_published_date</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;age&#39;</span><span class="p">]),</span>
+ <span class="p">}</span>
+ <span class="k">if</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">][</span><span class="s1">&#39;src&#39;</span><span class="p">]</span>
+ <span class="n">result_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">result_list</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_images</span><span class="p">(</span><span class="n">json_resp</span><span class="p">):</span>
+ <span class="n">result_list</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_resp</span><span class="p">[</span><span class="s2">&quot;results&quot;</span><span class="p">]:</span>
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;resolution&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;properties&#39;</span><span class="p">][</span><span class="s1">&#39;format&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;source&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;source&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;properties&#39;</span><span class="p">][</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail_src&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">][</span><span class="s1">&#39;src&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="n">result_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">result_list</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_videos</span><span class="p">(</span><span class="n">json_resp</span><span class="p">):</span>
+ <span class="n">result_list</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_resp</span><span class="p">[</span><span class="s2">&quot;results&quot;</span><span class="p">]:</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span>
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;length&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;video&#39;</span><span class="p">][</span><span class="s1">&#39;duration&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;duration&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;video&#39;</span><span class="p">][</span><span class="s1">&#39;duration&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">_extract_published_date</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;age&#39;</span><span class="p">]),</span>
+ <span class="p">}</span>
+
+ <span class="k">if</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">][</span><span class="s1">&#39;src&#39;</span><span class="p">]</span>
+
+ <span class="n">iframe_src</span> <span class="o">=</span> <span class="n">get_embeded_stream_url</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">iframe_src</span><span class="p">:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;iframe_src&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">iframe_src</span>
+
+ <span class="n">result_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">result_list</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/brave.html#searx.engines.brave.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch :ref:`languages &lt;brave languages&gt;` and :ref:`regions &lt;brave</span>
+<span class="sd"> regions&gt;` from Brave.&quot;&quot;&quot;</span>
+
+ <span class="c1"># pylint: disable=import-outside-toplevel, too-many-branches</span>
+
+ <span class="kn">import</span> <span class="nn">babel.languages</span>
+ <span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">region_tag</span><span class="p">,</span> <span class="n">language_tag</span>
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ui_lang&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;Accept-Encoding&#39;</span><span class="p">:</span> <span class="s1">&#39;gzip, deflate&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="n">lang_map</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;no&#39;</span><span class="p">:</span> <span class="s1">&#39;nb&#39;</span><span class="p">}</span> <span class="c1"># norway</span>
+
+ <span class="c1"># languages (UI)</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://search.brave.com/settings&#39;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from Brave is not OK.&quot;</span><span class="p">)</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">for</span> <span class="n">option</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//section//option[@value=&quot;en-us&quot;]/../option&#39;</span><span class="p">):</span>
+
+ <span class="n">ui_lang</span> <span class="o">=</span> <span class="n">option</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">)</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">l</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">ui_lang</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">l</span><span class="o">.</span><span class="n">territory</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">ui_lang</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">))</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">ui_lang</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">))</span>
+
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t determine babel locale of Brave&#39;s (UI) language </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">ui_lang</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ui_lang&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">ui_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">ui_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ui_lang&quot;</span><span class="p">][</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">ui_lang</span>
+
+ <span class="c1"># search regions of brave</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://cdn.search.brave.com/serp/v2/_app/immutable/chunks/parameters.734c106a.js&#39;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from Brave is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">country_js</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">[</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;options:{all&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="nb">len</span><span class="p">(</span><span class="s1">&#39;options:&#39;</span><span class="p">)</span> <span class="p">:]</span> <span class="c1"># type: ignore</span>
+ <span class="n">country_js</span> <span class="o">=</span> <span class="n">country_js</span><span class="p">[:</span> <span class="n">country_js</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;},k={default&quot;</span><span class="p">)]</span>
+ <span class="n">country_tags</span> <span class="o">=</span> <span class="n">js_variable_to_python</span><span class="p">(</span><span class="n">country_js</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">country_tags</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;all&#39;</span>
+ <span class="k">continue</span>
+ <span class="n">country_tag</span> <span class="o">=</span> <span class="n">v</span><span class="p">[</span><span class="s1">&#39;value&#39;</span><span class="p">]</span>
+
+ <span class="c1"># add official languages of the country ..</span>
+ <span class="k">for</span> <span class="n">lang_tag</span> <span class="ow">in</span> <span class="n">babel</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get_official_languages</span><span class="p">(</span><span class="n">country_tag</span><span class="p">,</span> <span class="n">de_facto</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
+ <span class="n">lang_tag</span> <span class="o">=</span> <span class="n">lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">lang_tag</span><span class="p">,</span> <span class="n">lang_tag</span><span class="p">)</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">_</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">lang_tag</span><span class="p">,</span> <span class="n">country_tag</span><span class="o">.</span><span class="n">upper</span><span class="p">())))</span>
+ <span class="c1"># print(&quot;%-20s: %s &lt;-- %s&quot; % (v[&#39;label&#39;], country_tag, sxng_tag))</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">country_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">country_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">country_tag</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/command.html b/_modules/searx/engines/command.html
new file mode 100644
index 000000000..b52de808b
--- /dev/null
+++ b/_modules/searx/engines/command.html
@@ -0,0 +1,355 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.command &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.command</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.command</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;With *command engines* administrators can run engines to integrate arbitrary</span>
+<span class="sd">shell commands.</span>
+
+<span class="sd">.. attention::</span>
+
+<span class="sd"> When creating and enabling a ``command`` engine on a public instance, you</span>
+<span class="sd"> must be careful to avoid leaking private data.</span>
+
+<span class="sd">The easiest solution is to limit the access by setting ``tokens`` as described</span>
+<span class="sd">in section :ref:`private engines`. The engine base is flexible. Only your</span>
+<span class="sd">imagination can limit the power of this engine (and maybe security concerns).</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The following options are available:</span>
+
+<span class="sd">``command``:</span>
+<span class="sd"> A comma separated list of the elements of the command. A special token</span>
+<span class="sd"> ``{{QUERY}}`` tells where to put the search terms of the user. Example:</span>
+
+<span class="sd"> .. code:: yaml</span>
+
+<span class="sd"> [&#39;ls&#39;, &#39;-l&#39;, &#39;-h&#39;, &#39;{{QUERY}}&#39;]</span>
+
+<span class="sd">``delimiter``:</span>
+<span class="sd"> A mapping containing a delimiter ``char`` and the *titles* of each element in</span>
+<span class="sd"> ``keys``.</span>
+
+<span class="sd">``parse_regex``:</span>
+<span class="sd"> A dict containing the regular expressions for each result key.</span>
+
+<span class="sd">``query_type``:</span>
+
+<span class="sd"> The expected type of user search terms. Possible values: ``path`` and</span>
+<span class="sd"> ``enum``.</span>
+
+<span class="sd"> ``path``:</span>
+<span class="sd"> Checks if the user provided path is inside the working directory. If not,</span>
+<span class="sd"> the query is not executed.</span>
+
+<span class="sd"> ``enum``:</span>
+<span class="sd"> Is a list of allowed search terms. If the user submits something which is</span>
+<span class="sd"> not included in the list, the query returns an error.</span>
+
+<span class="sd">``query_enum``:</span>
+<span class="sd"> A list containing allowed search terms if ``query_type`` is set to ``enum``.</span>
+
+<span class="sd">``working_dir``:</span>
+<span class="sd"> The directory where the command has to be executed. Default: ``./``.</span>
+
+<span class="sd">``result_separator``:</span>
+<span class="sd"> The character that separates results. Default: ``\\n``.</span>
+
+<span class="sd">Example</span>
+<span class="sd">=======</span>
+
+<span class="sd">The example engine below can be used to find files with a specific name in the</span>
+<span class="sd">configured working directory:</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: find</span>
+<span class="sd"> engine: command</span>
+<span class="sd"> command: [&#39;find&#39;, &#39;.&#39;, &#39;-name&#39;, &#39;{{QUERY}}&#39;]</span>
+<span class="sd"> query_type: path</span>
+<span class="sd"> shortcut: fnd</span>
+<span class="sd"> delimiter:</span>
+<span class="sd"> chars: &#39; &#39;</span>
+<span class="sd"> keys: [&#39;line&#39;]</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">from</span> <span class="nn">os.path</span> <span class="kn">import</span> <span class="n">expanduser</span><span class="p">,</span> <span class="n">isabs</span><span class="p">,</span> <span class="n">realpath</span><span class="p">,</span> <span class="n">commonprefix</span>
+<span class="kn">from</span> <span class="nn">shlex</span> <span class="kn">import</span> <span class="n">split</span> <span class="k">as</span> <span class="n">shlex_split</span>
+<span class="kn">from</span> <span class="nn">subprocess</span> <span class="kn">import</span> <span class="n">Popen</span><span class="p">,</span> <span class="n">PIPE</span>
+<span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Thread</span>
+
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">logger</span>
+
+
+<span class="n">engine_type</span> <span class="o">=</span> <span class="s1">&#39;offline&#39;</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">command</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">delimiter</span> <span class="o">=</span> <span class="p">{}</span>
+<span class="n">parse_regex</span> <span class="o">=</span> <span class="p">{}</span>
+<span class="n">query_type</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="n">query_enum</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">environment_variables</span> <span class="o">=</span> <span class="p">{}</span>
+<span class="n">working_dir</span> <span class="o">=</span> <span class="n">realpath</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)</span>
+<span class="n">result_separator</span> <span class="o">=</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span>
+<span class="n">result_template</span> <span class="o">=</span> <span class="s1">&#39;key-value.html&#39;</span>
+<span class="n">timeout</span> <span class="o">=</span> <span class="mf">4.0</span>
+
+<span class="n">_command_logger</span> <span class="o">=</span> <span class="n">logger</span><span class="o">.</span><span class="n">getChild</span><span class="p">(</span><span class="s1">&#39;command&#39;</span><span class="p">)</span>
+<span class="n">_compiled_parse_regex</span> <span class="o">=</span> <span class="p">{}</span>
+
+
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">):</span>
+ <span class="n">check_parsing_options</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="s1">&#39;command&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;engine command : missing configuration key: command&#39;</span><span class="p">)</span>
+
+ <span class="k">global</span> <span class="n">command</span><span class="p">,</span> <span class="n">working_dir</span><span class="p">,</span> <span class="n">delimiter</span><span class="p">,</span> <span class="n">parse_regex</span><span class="p">,</span> <span class="n">environment_variables</span> <span class="c1"># pylint: disable=global-statement</span>
+
+ <span class="n">command</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;command&#39;</span><span class="p">]</span>
+
+ <span class="k">if</span> <span class="s1">&#39;working_dir&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="n">working_dir</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;working_dir&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">isabs</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;working_dir&#39;</span><span class="p">]):</span>
+ <span class="n">working_dir</span> <span class="o">=</span> <span class="n">realpath</span><span class="p">(</span><span class="n">working_dir</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="s1">&#39;parse_regex&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="n">parse_regex</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;parse_regex&#39;</span><span class="p">]</span>
+ <span class="k">for</span> <span class="n">result_key</span><span class="p">,</span> <span class="n">regex</span> <span class="ow">in</span> <span class="n">parse_regex</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="n">_compiled_parse_regex</span><span class="p">[</span><span class="n">result_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="n">regex</span><span class="p">,</span> <span class="n">flags</span><span class="o">=</span><span class="n">re</span><span class="o">.</span><span class="n">MULTILINE</span><span class="p">)</span>
+ <span class="k">if</span> <span class="s1">&#39;delimiter&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="n">delimiter</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;delimiter&#39;</span><span class="p">]</span>
+
+ <span class="k">if</span> <span class="s1">&#39;environment_variables&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="n">environment_variables</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;environment_variables&#39;</span><span class="p">]</span>
+
+
+<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">cmd</span> <span class="o">=</span> <span class="n">_get_command_to_run</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">cmd</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">reader_thread</span> <span class="o">=</span> <span class="n">Thread</span><span class="p">(</span><span class="n">target</span><span class="o">=</span><span class="n">_get_results_from_process</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(</span><span class="n">results</span><span class="p">,</span> <span class="n">cmd</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]))</span>
+ <span class="n">reader_thread</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
+ <span class="n">reader_thread</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="k">def</span> <span class="nf">_get_command_to_run</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
+ <span class="n">params</span> <span class="o">=</span> <span class="n">shlex_split</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+ <span class="n">__check_query_params</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
+
+ <span class="n">cmd</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">command</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">c</span> <span class="o">==</span> <span class="s1">&#39;{{QUERY}}&#39;</span><span class="p">:</span>
+ <span class="n">cmd</span><span class="o">.</span><span class="n">extend</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">cmd</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">c</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">cmd</span>
+
+
+<span class="k">def</span> <span class="nf">_get_results_from_process</span><span class="p">(</span><span class="n">results</span><span class="p">,</span> <span class="n">cmd</span><span class="p">,</span> <span class="n">pageno</span><span class="p">):</span>
+ <span class="n">leftover</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
+ <span class="n">start</span><span class="p">,</span> <span class="n">end</span> <span class="o">=</span> <span class="n">__get_results_limits</span><span class="p">(</span><span class="n">pageno</span><span class="p">)</span>
+ <span class="k">with</span> <span class="n">Popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">stdout</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">stderr</span><span class="o">=</span><span class="n">PIPE</span><span class="p">,</span> <span class="n">env</span><span class="o">=</span><span class="n">environment_variables</span><span class="p">)</span> <span class="k">as</span> <span class="n">process</span><span class="p">:</span>
+ <span class="n">line</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
+ <span class="k">while</span> <span class="n">line</span><span class="p">:</span>
+ <span class="n">buf</span> <span class="o">=</span> <span class="n">leftover</span> <span class="o">+</span> <span class="n">line</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span>
+ <span class="n">raw_results</span> <span class="o">=</span> <span class="n">buf</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">result_separator</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">raw_results</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]:</span>
+ <span class="n">leftover</span> <span class="o">=</span> <span class="n">raw_results</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="n">raw_results</span> <span class="o">=</span> <span class="n">raw_results</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+
+ <span class="k">for</span> <span class="n">raw_result</span> <span class="ow">in</span> <span class="n">raw_results</span><span class="p">:</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">__parse_single_result</span><span class="p">(</span><span class="n">raw_result</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">_command_logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;skipped result:&#39;</span><span class="p">,</span> <span class="n">raw_result</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="k">if</span> <span class="n">start</span> <span class="o">&lt;=</span> <span class="n">count</span> <span class="ow">and</span> <span class="n">count</span> <span class="o">&lt;=</span> <span class="n">end</span><span class="p">:</span> <span class="c1"># pylint: disable=chained-comparison</span>
+ <span class="n">result</span><span class="p">[</span><span class="s1">&#39;template&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">result_template</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
+
+ <span class="n">count</span> <span class="o">+=</span> <span class="mi">1</span>
+ <span class="k">if</span> <span class="n">end</span> <span class="o">&lt;</span> <span class="n">count</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+ <span class="n">line</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
+
+ <span class="n">return_code</span> <span class="o">=</span> <span class="n">process</span><span class="o">.</span><span class="n">wait</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">return_code</span> <span class="o">!=</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s1">&#39;non-zero return code when running command&#39;</span><span class="p">,</span> <span class="n">cmd</span><span class="p">,</span> <span class="n">return_code</span><span class="p">)</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">__get_results_limits</span><span class="p">(</span><span class="n">pageno</span><span class="p">):</span>
+ <span class="n">start</span> <span class="o">=</span> <span class="p">(</span><span class="n">pageno</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span>
+ <span class="n">end</span> <span class="o">=</span> <span class="n">start</span> <span class="o">+</span> <span class="mi">9</span>
+ <span class="k">return</span> <span class="n">start</span><span class="p">,</span> <span class="n">end</span>
+
+
+<span class="k">def</span> <span class="nf">__check_query_params</span><span class="p">(</span><span class="n">params</span><span class="p">):</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">query_type</span><span class="p">:</span>
+ <span class="k">return</span>
+
+ <span class="k">if</span> <span class="n">query_type</span> <span class="o">==</span> <span class="s1">&#39;path&#39;</span><span class="p">:</span>
+ <span class="n">query_path</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="n">query_path</span> <span class="o">=</span> <span class="n">expanduser</span><span class="p">(</span><span class="n">query_path</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">commonprefix</span><span class="p">([</span><span class="n">realpath</span><span class="p">(</span><span class="n">query_path</span><span class="p">),</span> <span class="n">working_dir</span><span class="p">])</span> <span class="o">!=</span> <span class="n">working_dir</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;requested path is outside of configured working directory&#39;</span><span class="p">)</span>
+ <span class="k">elif</span> <span class="n">query_type</span> <span class="o">==</span> <span class="s1">&#39;enum&#39;</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">query_enum</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">param</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">param</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">query_enum</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;submitted query params is not allowed&#39;</span><span class="p">,</span> <span class="n">param</span><span class="p">,</span> <span class="s1">&#39;allowed params:&#39;</span><span class="p">,</span> <span class="n">query_enum</span><span class="p">)</span>
+
+
+<div class="viewcode-block" id="check_parsing_options">
+<a class="viewcode-back" href="../../../dev/engines/offline/command-line-engines.html#searx.engines.command.check_parsing_options">[docs]</a>
+<span class="k">def</span> <span class="nf">check_parsing_options</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Checks if delimiter based parsing or regex parsing is configured correctly&quot;&quot;&quot;</span>
+
+ <span class="k">if</span> <span class="s1">&#39;delimiter&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span> <span class="ow">and</span> <span class="s1">&#39;parse_regex&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;failed to init settings for parsing lines: missing delimiter or parse_regex&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="s1">&#39;delimiter&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span> <span class="ow">and</span> <span class="s1">&#39;parse_regex&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;failed to init settings for parsing lines: too many settings&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="s1">&#39;delimiter&#39;</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="k">if</span> <span class="s1">&#39;chars&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;delimiter&#39;</span><span class="p">]</span> <span class="ow">or</span> <span class="s1">&#39;keys&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;delimiter&#39;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">__parse_single_result</span><span class="p">(</span><span class="n">raw_result</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parses command line output based on configuration&quot;&quot;&quot;</span>
+
+ <span class="n">result</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="k">if</span> <span class="n">delimiter</span><span class="p">:</span>
+ <span class="n">elements</span> <span class="o">=</span> <span class="n">raw_result</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">delimiter</span><span class="p">[</span><span class="s1">&#39;chars&#39;</span><span class="p">],</span> <span class="n">maxsplit</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">delimiter</span><span class="p">[</span><span class="s1">&#39;keys&#39;</span><span class="p">])</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">elements</span><span class="p">)</span> <span class="o">!=</span> <span class="nb">len</span><span class="p">(</span><span class="n">delimiter</span><span class="p">[</span><span class="s1">&#39;keys&#39;</span><span class="p">]):</span>
+ <span class="k">return</span> <span class="p">{}</span>
+ <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">elements</span><span class="p">)):</span> <span class="c1"># pylint: disable=consider-using-enumerate</span>
+ <span class="n">result</span><span class="p">[</span><span class="n">delimiter</span><span class="p">[</span><span class="s1">&#39;keys&#39;</span><span class="p">][</span><span class="n">i</span><span class="p">]]</span> <span class="o">=</span> <span class="n">elements</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
+
+ <span class="k">if</span> <span class="n">parse_regex</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">result_key</span><span class="p">,</span> <span class="n">regex</span> <span class="ow">in</span> <span class="n">_compiled_parse_regex</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="n">found</span> <span class="o">=</span> <span class="n">regex</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">raw_result</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">found</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">{}</span>
+ <span class="n">result</span><span class="p">[</span><span class="n">result_key</span><span class="p">]</span> <span class="o">=</span> <span class="n">raw_result</span><span class="p">[</span><span class="n">found</span><span class="o">.</span><span class="n">start</span><span class="p">()</span> <span class="p">:</span> <span class="n">found</span><span class="o">.</span><span class="n">end</span><span class="p">()]</span>
+
+ <span class="k">return</span> <span class="n">result</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/dailymotion.html b/_modules/searx/engines/dailymotion.html
new file mode 100644
index 000000000..9c873dcb8
--- /dev/null
+++ b/_modules/searx/engines/dailymotion.html
@@ -0,0 +1,362 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.dailymotion &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.dailymotion</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.dailymotion</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">Dailymotion (Videos)</span>
+<span class="sd">~~~~~~~~~~~~~~~~~~~~</span>
+
+<span class="sd">.. _REST GET: https://developers.dailymotion.com/tools/</span>
+<span class="sd">.. _Global API Parameters: https://developers.dailymotion.com/api/#global-parameters</span>
+<span class="sd">.. _Video filters API: https://developers.dailymotion.com/api/#video-filters</span>
+<span class="sd">.. _Fields selection: https://developers.dailymotion.com/api/#fields-selection</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">import</span> <span class="nn">time</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span><span class="p">,</span> <span class="n">raise_for_httperror</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">html_to_text</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineAPIException</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">region_tag</span><span class="p">,</span> <span class="n">language_tag</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.dailymotion.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q769222&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.dailymotion.com/developer&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;videos&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">number_of_results</span> <span class="o">=</span> <span class="mi">10</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_delta_dict</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;day&quot;</span><span class="p">:</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span>
+ <span class="s2">&quot;week&quot;</span><span class="p">:</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">7</span><span class="p">),</span>
+ <span class="s2">&quot;month&quot;</span><span class="p">:</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">31</span><span class="p">),</span>
+ <span class="s2">&quot;year&quot;</span><span class="p">:</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="mi">365</span><span class="p">),</span>
+<span class="p">}</span>
+
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="mi">2</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;is_created_for_kids&#39;</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">},</span>
+ <span class="mi">1</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;is_created_for_kids&#39;</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">},</span>
+ <span class="mi">0</span><span class="p">:</span> <span class="p">{},</span>
+<span class="p">}</span>
+<span class="sd">&quot;&quot;&quot;True if this video is &quot;Created for Kids&quot; / intends to target an audience</span>
+<span class="sd">under the age of 16 (``is_created_for_kids`` in `Video filters API`_ )</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">family_filter_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">,</span>
+ <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">,</span>
+ <span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;false&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="sd">&quot;&quot;&quot;By default, the family filter is turned on. Setting this parameter to</span>
+<span class="sd">``false`` will stop filtering-out explicit content from searches and global</span>
+<span class="sd">contexts (``family_filter`` in `Global API Parameters`_ ).</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">result_fields</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="s1">&#39;allow_embed&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;description&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;created_time&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;duration&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail_360_url&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;id&#39;</span><span class="p">,</span>
+<span class="p">]</span>
+<span class="sd">&quot;&quot;&quot;`Fields selection`_, by default, a few fields are returned. To request more</span>
+<span class="sd">specific fields, the ``fields`` parameter is used with the list of fields</span>
+<span class="sd">SearXNG needs in the response to build a video result list.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">search_url</span> <span class="o">=</span> <span class="s1">&#39;https://api.dailymotion.com/videos?&#39;</span>
+<span class="sd">&quot;&quot;&quot;URL to retrieve a list of videos.</span>
+
+<span class="sd">- `REST GET`_</span>
+<span class="sd">- `Global API Parameters`_</span>
+<span class="sd">- `Video filters API`_</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">iframe_src</span> <span class="o">=</span> <span class="s2">&quot;https://www.dailymotion.com/embed/video/</span><span class="si">{video_id}</span><span class="s2">&quot;</span>
+<span class="sd">&quot;&quot;&quot;URL template to embed video in SearXNG&#39;s result list.&quot;&quot;&quot;</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">query</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">False</span>
+
+ <span class="n">eng_region</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en_US&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span>
+
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;search&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;family_filter&#39;</span><span class="p">:</span> <span class="n">family_filter_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">],</span> <span class="s1">&#39;false&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;thumbnail_ratio&#39;</span><span class="p">:</span> <span class="s1">&#39;original&#39;</span><span class="p">,</span> <span class="c1"># original|widescreen|square</span>
+ <span class="c1"># https://developers.dailymotion.com/api/#video-filters</span>
+ <span class="s1">&#39;languages&#39;</span><span class="p">:</span> <span class="n">eng_lang</span><span class="p">,</span>
+ <span class="s1">&#39;page&#39;</span><span class="p">:</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;password_protected&#39;</span><span class="p">:</span> <span class="s1">&#39;false&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;private&#39;</span><span class="p">:</span> <span class="s1">&#39;false&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sort&#39;</span><span class="p">:</span> <span class="s1">&#39;relevance&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;limit&#39;</span><span class="p">:</span> <span class="n">number_of_results</span><span class="p">,</span>
+ <span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result_fields</span><span class="p">),</span>
+ <span class="p">}</span>
+
+ <span class="n">args</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">safesearch_params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">],</span> <span class="p">{}))</span>
+
+ <span class="c1"># Don&#39;t add localization and country arguments if the user does select a</span>
+ <span class="c1"># language (:de, :en, ..)</span>
+
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="c1"># https://developers.dailymotion.com/api/#global-parameters</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;localization&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_region</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;country&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_region</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
+ <span class="c1"># Insufficient rights for the `ams_country&#39; parameter of route `GET /videos&#39;</span>
+ <span class="c1"># &#39;ams_country&#39;: eng_region.split(&#39;_&#39;)[1],</span>
+
+ <span class="n">time_delta</span> <span class="o">=</span> <span class="n">time_delta_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;time_range&quot;</span><span class="p">])</span>
+ <span class="k">if</span> <span class="n">time_delta</span><span class="p">:</span>
+ <span class="n">created_after</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">time_delta</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;created_after&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timestamp</span><span class="p">(</span><span class="n">created_after</span><span class="p">)</span>
+
+ <span class="n">query_str</span> <span class="o">=</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span> <span class="o">+</span> <span class="n">query_str</span>
+
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="c1"># get response from search-request</span>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">search_res</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+
+ <span class="c1"># check for an API error</span>
+ <span class="k">if</span> <span class="s1">&#39;error&#39;</span> <span class="ow">in</span> <span class="n">search_res</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="n">SearxEngineAPIException</span><span class="p">(</span><span class="n">search_res</span><span class="p">[</span><span class="s1">&#39;error&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">))</span>
+
+ <span class="n">raise_for_httperror</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="c1"># parse results</span>
+ <span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;list&#39;</span><span class="p">,</span> <span class="p">[]):</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">res</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">res</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="n">html_to_text</span><span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="s1">&#39;description&#39;</span><span class="p">])</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">300</span><span class="p">:</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="p">[:</span><span class="mi">300</span><span class="p">]</span> <span class="o">+</span> <span class="s1">&#39;...&#39;</span>
+
+ <span class="n">publishedDate</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">res</span><span class="p">[</span><span class="s1">&#39;created_time&#39;</span><span class="p">],</span> <span class="kc">None</span><span class="p">)</span>
+
+ <span class="n">length</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span><span class="p">(</span><span class="n">res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;duration&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">length</span><span class="o">.</span><span class="n">tm_hour</span><span class="p">:</span>
+ <span class="n">length</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%H:%M:%S&quot;</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">length</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%M:%S&quot;</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">res</span><span class="p">[</span><span class="s1">&#39;thumbnail_360_url&#39;</span><span class="p">]</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">thumbnail</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;http://&quot;</span><span class="p">,</span> <span class="s2">&quot;https://&quot;</span><span class="p">)</span>
+
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">publishedDate</span><span class="p">,</span>
+ <span class="s1">&#39;length&#39;</span><span class="p">:</span> <span class="n">length</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="c1"># HINT: no mater what the value is, without API token videos can&#39;t shown</span>
+ <span class="c1"># embedded</span>
+ <span class="k">if</span> <span class="n">res</span><span class="p">[</span><span class="s1">&#39;allow_embed&#39;</span><span class="p">]:</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;iframe_src&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">iframe_src</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">video_id</span><span class="o">=</span><span class="n">res</span><span class="p">[</span><span class="s1">&#39;id&#39;</span><span class="p">])</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="c1"># return results</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/dailymotion.html#searx.engines.dailymotion.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch locales &amp; languages from dailymotion.</span>
+
+<span class="sd"> Locales fetched from `api/locales &lt;https://api.dailymotion.com/locales&gt;`_.</span>
+<span class="sd"> There are duplications in the locale codes returned from Dailymotion which</span>
+<span class="sd"> can be ignored::</span>
+
+<span class="sd"> en_EN --&gt; en_GB, en_US</span>
+<span class="sd"> ar_AA --&gt; ar_EG, ar_AE, ar_SA</span>
+
+<span class="sd"> The language list `api/languages &lt;https://api.dailymotion.com/languages&gt;`_</span>
+<span class="sd"> contains over 7000 *languages* codes (see PR1071_). We use only those</span>
+<span class="sd"> language codes that are used in the locales.</span>
+
+<span class="sd"> .. _PR1071: https://github.com/searxng/searxng/pull/1071</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://api.dailymotion.com/locales&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from dailymotion/locales is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()[</span><span class="s1">&#39;list&#39;</span><span class="p">]:</span> <span class="c1"># type: ignore</span>
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;locale&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;en_EN&#39;</span><span class="p">,</span> <span class="s1">&#39;ar_AA&#39;</span><span class="p">):</span>
+ <span class="k">continue</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: item unknown --&gt; </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">item</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="n">locale_lang_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">values</span><span class="p">()]</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://api.dailymotion.com/languages&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from dailymotion/languages is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()[</span><span class="s1">&#39;list&#39;</span><span class="p">]:</span> <span class="c1"># type: ignore</span>
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;code&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="ow">in</span> <span class="n">locale_lang_list</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">))</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/demo_offline.html b/_modules/searx/engines/demo_offline.html
new file mode 100644
index 000000000..6dc673a98
--- /dev/null
+++ b/_modules/searx/engines/demo_offline.html
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.demo_offline &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.demo_offline</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.demo_offline</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Within this module we implement a *demo offline engine*. Do not look to</span>
+<span class="sd">close to the implementation, its just a simple example. To get in use of this</span>
+<span class="sd">*demo* engine add the following entry to your engines list in ``settings.yml``:</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: my offline engine</span>
+<span class="sd"> engine: demo_offline</span>
+<span class="sd"> shortcut: demo</span>
+<span class="sd"> disabled: false</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">json</span>
+
+<span class="n">engine_type</span> <span class="o">=</span> <span class="s1">&#39;offline&#39;</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">]</span>
+<span class="n">disabled</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">timeout</span> <span class="o">=</span> <span class="mf">2.0</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># if there is a need for globals, use a leading underline</span>
+<span class="n">_my_offline_engine</span> <span class="o">=</span> <span class="kc">None</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/demo/demo_offline.html#searx.engines.demo_offline.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Initialization of the (offline) engine. The origin of this demo engine is a</span>
+<span class="sd"> simple json string which is loaded in this example while the engine is</span>
+<span class="sd"> initialized.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">global</span> <span class="n">_my_offline_engine</span> <span class="c1"># pylint: disable=global-statement</span>
+
+ <span class="n">_my_offline_engine</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;[ {&quot;value&quot;: &quot;</span><span class="si">%s</span><span class="s1">&quot;}&#39;</span>
+ <span class="s1">&#39;, {&quot;value&quot;:&quot;first item&quot;}&#39;</span>
+ <span class="s1">&#39;, {&quot;value&quot;:&quot;second item&quot;}&#39;</span>
+ <span class="s1">&#39;, {&quot;value&quot;:&quot;third item&quot;}&#39;</span>
+ <span class="s1">&#39;]&#39;</span> <span class="o">%</span> <span class="n">engine_settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span>
+ <span class="p">)</span></div>
+
+
+
+<div class="viewcode-block" id="search">
+<a class="viewcode-back" href="../../../dev/engines/demo/demo_offline.html#searx.engines.demo_offline.search">[docs]</a>
+<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">request_params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Query (offline) engine and return results. Assemble the list of results from</span>
+<span class="sd"> your local engine. In this demo engine we ignore the &#39;query&#39; term, usual</span>
+<span class="sd"> you would pass the &#39;query&#39; term to your local engine to filter out the</span>
+<span class="sd"> results.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">ret_val</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">result_list</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">_my_offline_engine</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">result_list</span><span class="p">:</span>
+ <span class="n">entry</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;language&#39;</span><span class="p">:</span> <span class="n">request_params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;value&#39;</span><span class="p">:</span> <span class="n">row</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">),</span>
+ <span class="c1"># choose a result template or comment out to use the *default*</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;key-value.html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="n">ret_val</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">entry</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">ret_val</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/demo_online.html b/_modules/searx/engines/demo_online.html
new file mode 100644
index 000000000..32a50086c
--- /dev/null
+++ b/_modules/searx/engines/demo_online.html
@@ -0,0 +1,215 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.demo_online &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.demo_online</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.demo_online</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Within this module we implement a *demo online engine*. Do not look to</span>
+<span class="sd">close to the implementation, its just a simple example which queries `The Art</span>
+<span class="sd">Institute of Chicago &lt;https://www.artic.edu&gt;`_</span>
+
+<span class="sd">To get in use of this *demo* engine add the following entry to your engines</span>
+<span class="sd">list in ``settings.yml``:</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: my online engine</span>
+<span class="sd"> engine: demo_online</span>
+<span class="sd"> shortcut: demo</span>
+<span class="sd"> disabled: false</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">loads</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+
+<span class="n">engine_type</span> <span class="o">=</span> <span class="s1">&#39;online&#39;</span>
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">]</span>
+<span class="n">disabled</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">timeout</span> <span class="o">=</span> <span class="mf">2.0</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;images&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">page_size</span> <span class="o">=</span> <span class="mi">20</span>
+
+<span class="n">search_api</span> <span class="o">=</span> <span class="s1">&#39;https://api.artic.edu/api/v1/artworks/search?&#39;</span>
+<span class="n">image_api</span> <span class="o">=</span> <span class="s1">&#39;https://www.artic.edu/iiif/2/&#39;</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.artic.edu&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q239303&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;http://api.artic.edu/docs/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+
+<span class="c1"># if there is a need for globals, use a leading underline</span>
+<span class="n">_my_online_engine</span> <span class="o">=</span> <span class="kc">None</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/demo/demo_online.html#searx.engines.demo_online.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Initialization of the (online) engine. If no initialization is needed, drop</span>
+<span class="sd"> this init function.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">global</span> <span class="n">_my_online_engine</span> <span class="c1"># pylint: disable=global-statement</span>
+ <span class="n">_my_online_engine</span> <span class="o">=</span> <span class="n">engine_settings</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span></div>
+
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/demo/demo_online.html#searx.engines.demo_online.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Build up the ``params`` for the online request. In this example we build a</span>
+<span class="sd"> URL to fetch images from `artic.edu &lt;https://artic.edu&gt;`__</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;page&#39;</span><span class="p">:</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;fields&#39;</span><span class="p">:</span> <span class="s1">&#39;id,title,artist_display,medium_display,image_id,date_display,dimensions,artist_titles&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;limit&#39;</span><span class="p">:</span> <span class="n">page_size</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_api</span> <span class="o">+</span> <span class="n">args</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/demo/demo_online.html#searx.engines.demo_online.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse out the result items from the response. In this example we parse the</span>
+<span class="sd"> response from `api.artic.edu &lt;https://artic.edu&gt;`__ and filter out all</span>
+<span class="sd"> images.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]:</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;image_id&#39;</span><span class="p">]:</span>
+ <span class="k">continue</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="s1">&#39;https://artic.edu/artworks/</span><span class="si">%(id)s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">result</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s2">&quot; (</span><span class="si">%(date_display)s</span><span class="s2">) // </span><span class="si">%(artist_display)s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">result</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="s2">&quot;</span><span class="si">%(medium_display)s</span><span class="s2"> // </span><span class="si">%(dimensions)s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">result</span><span class="p">,</span>
+ <span class="s1">&#39;author&#39;</span><span class="p">:</span> <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;artist_titles&#39;</span><span class="p">]),</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">image_api</span> <span class="o">+</span> <span class="s1">&#39;/</span><span class="si">%(image_id)s</span><span class="s1">/full/843,/0/default.jpg&#39;</span> <span class="o">%</span> <span class="n">result</span><span class="p">,</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/duckduckgo.html b/_modules/searx/engines/duckduckgo.html
new file mode 100644
index 000000000..77a523617
--- /dev/null
+++ b/_modules/searx/engines/duckduckgo.html
@@ -0,0 +1,632 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.duckduckgo &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.duckduckgo</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.duckduckgo</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">DuckDuckGo WEB</span>
+<span class="sd">~~~~~~~~~~~~~~</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span><span class="p">,</span> <span class="n">quote_plus</span>
+<span class="kn">import</span> <span class="nn">json</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+<span class="kn">import</span> <span class="nn">lxml.html</span>
+
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">locales</span><span class="p">,</span>
+ <span class="n">redislib</span><span class="p">,</span>
+ <span class="n">external_bang</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">extr</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">redisdb</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineCaptchaException</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://lite.duckduckgo.com/lite/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q12805&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="sd">&quot;&quot;&quot;DuckDuckGo-Lite tries to guess user&#39;s preferred language from the HTTP</span>
+<span class="sd">``Accept-Language``. Optional the user can select a region filter (but not a</span>
+<span class="sd">language).</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># user can&#39;t select but the results are filtered</span>
+
+<span class="n">url</span> <span class="o">=</span> <span class="s2">&quot;https://html.duckduckgo.com/html&quot;</span>
+
+<span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span> <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;m&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="s1">&#39;y&#39;</span><span class="p">}</span>
+<span class="n">form_data</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;v&#39;</span><span class="p">:</span> <span class="s1">&#39;l&#39;</span><span class="p">,</span> <span class="s1">&#39;api&#39;</span><span class="p">:</span> <span class="s1">&#39;d.js&#39;</span><span class="p">,</span> <span class="s1">&#39;o&#39;</span><span class="p">:</span> <span class="s1">&#39;json&#39;</span><span class="p">}</span>
+<span class="n">__CACHE</span> <span class="o">=</span> <span class="p">[]</span>
+
+
+<span class="k">def</span> <span class="nf">_cache_key</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">region</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;SearXNG_ddg_web_vqd&#39;</span> <span class="o">+</span> <span class="n">redislib</span><span class="o">.</span><span class="n">secret_hash</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">//</span><span class="si">{</span><span class="n">region</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+
+
+<div class="viewcode-block" id="cache_vqd">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo.cache_vqd">[docs]</a>
+<span class="k">def</span> <span class="nf">cache_vqd</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">region</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">value</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Caches a ``vqd`` value from a query.&quot;&quot;&quot;</span>
+ <span class="n">c</span> <span class="o">=</span> <span class="n">redisdb</span><span class="o">.</span><span class="n">client</span><span class="p">()</span>
+ <span class="k">if</span> <span class="n">c</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;VALKEY cache vqd value: </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">)&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">region</span><span class="p">)</span>
+ <span class="n">c</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">_cache_key</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">region</span><span class="p">),</span> <span class="n">value</span><span class="p">,</span> <span class="n">ex</span><span class="o">=</span><span class="mi">600</span><span class="p">)</span>
+
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;MEM cache vqd value: </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">)&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">region</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">__CACHE</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">100</span><span class="p">:</span> <span class="c1"># cache vqd from last 100 queries</span>
+ <span class="n">__CACHE</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+ <span class="n">__CACHE</span><span class="o">.</span><span class="n">append</span><span class="p">((</span><span class="n">_cache_key</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">region</span><span class="p">),</span> <span class="n">value</span><span class="p">))</span></div>
+
+
+
+<div class="viewcode-block" id="get_vqd">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo.get_vqd">[docs]</a>
+<span class="k">def</span> <span class="nf">get_vqd</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">region</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">force_request</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns the ``vqd`` that fits to the *query*.</span>
+
+<span class="sd"> :param query: The query term</span>
+<span class="sd"> :param region: DDG&#39;s region code</span>
+<span class="sd"> :param force_request: force a request to get a vqd value from DDG</span>
+
+<span class="sd"> TL;DR; the ``vqd`` value is needed to pass DDG&#39;s bot protection and is used</span>
+<span class="sd"> by all request to DDG:</span>
+
+<span class="sd"> - DuckDuckGo Lite: ``https://lite.duckduckgo.com/lite`` (POST form data)</span>
+<span class="sd"> - DuckDuckGo Web: ``https://links.duckduckgo.com/d.js?q=...&amp;vqd=...``</span>
+<span class="sd"> - DuckDuckGo Images: ``https://duckduckgo.com/i.js??q=...&amp;vqd=...``</span>
+<span class="sd"> - DuckDuckGo Videos: ``https://duckduckgo.com/v.js??q=...&amp;vqd=...``</span>
+<span class="sd"> - DuckDuckGo News: ``https://duckduckgo.com/news.js??q=...&amp;vqd=...``</span>
+
+<span class="sd"> DDG&#39;s bot detection is sensitive to the ``vqd`` value. For some search terms</span>
+<span class="sd"> (such as extremely long search terms that are often sent by bots), no ``vqd``</span>
+<span class="sd"> value can be determined.</span>
+
+<span class="sd"> If SearXNG cannot determine a ``vqd`` value, then no request should go out</span>
+<span class="sd"> to DDG.</span>
+
+<span class="sd"> .. attention::</span>
+
+<span class="sd"> A request with a wrong ``vqd`` value leads to DDG temporarily putting</span>
+<span class="sd"> SearXNG&#39;s IP on a block list.</span>
+
+<span class="sd"> Requests from IPs in this block list run into timeouts. Not sure, but it</span>
+<span class="sd"> seems the block list is a sliding window: to get my IP rid from the bot list</span>
+<span class="sd"> I had to cool down my IP for 1h (send no requests from that IP to DDG).</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="n">_cache_key</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">region</span><span class="p">)</span>
+
+ <span class="n">c</span> <span class="o">=</span> <span class="n">redisdb</span><span class="o">.</span><span class="n">client</span><span class="p">()</span>
+ <span class="k">if</span> <span class="n">c</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">value</span> <span class="ow">or</span> <span class="n">value</span> <span class="o">==</span> <span class="sa">b</span><span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;re-use CACHED vqd value: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+ <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">__CACHE</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">k</span> <span class="o">==</span> <span class="n">key</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;MEM re-use CACHED vqd value: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+ <span class="k">if</span> <span class="n">force_request</span><span class="p">:</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;https://duckduckgo.com/?q=</span><span class="si">{</span><span class="n">quote_plus</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">extr</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="s1">&#39;vqd=&quot;&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;vqd value from DDG request: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+ <span class="n">cache_vqd</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">region</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+ <span class="k">return</span> <span class="kc">None</span></div>
+
+
+
+<div class="viewcode-block" id="get_ddg_lang">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo.get_ddg_lang">[docs]</a>
+<span class="k">def</span> <span class="nf">get_ddg_lang</span><span class="p">(</span><span class="n">eng_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">,</span> <span class="n">sxng_locale</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;en_US&#39;</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get DuckDuckGo&#39;s language identifier from SearXNG&#39;s locale.</span>
+
+<span class="sd"> DuckDuckGo defines its languages by region codes (see</span>
+<span class="sd"> :py:obj:`fetch_traits`).</span>
+
+<span class="sd"> To get region and language of a DDG service use:</span>
+
+<span class="sd"> .. code: python</span>
+
+<span class="sd"> eng_region = traits.get_region(params[&#39;searxng_locale&#39;], traits.all_locale)</span>
+<span class="sd"> eng_lang = get_ddg_lang(traits, params[&#39;searxng_locale&#39;])</span>
+
+<span class="sd"> It might confuse, but the ``l`` value of the cookie is what SearXNG calls</span>
+<span class="sd"> the *region*:</span>
+
+<span class="sd"> .. code:: python</span>
+
+<span class="sd"> # !ddi paris :es-AR --&gt; {&#39;ad&#39;: &#39;es_AR&#39;, &#39;ah&#39;: &#39;ar-es&#39;, &#39;l&#39;: &#39;ar-es&#39;}</span>
+<span class="sd"> params[&#39;cookies&#39;][&#39;ad&#39;] = eng_lang</span>
+<span class="sd"> params[&#39;cookies&#39;][&#39;ah&#39;] = eng_region</span>
+<span class="sd"> params[&#39;cookies&#39;][&#39;l&#39;] = eng_region</span>
+
+<span class="sd"> .. hint::</span>
+
+<span class="sd"> `DDG-lite &lt;https://lite.duckduckgo.com/lite&gt;`__ and the *no Javascript*</span>
+<span class="sd"> page https://html.duckduckgo.com/html do not offer a language selection</span>
+<span class="sd"> to the user, only a region can be selected by the user (``eng_region``</span>
+<span class="sd"> from the example above). DDG-lite and *no Javascript* store the selected</span>
+<span class="sd"> region in a cookie::</span>
+
+<span class="sd"> params[&#39;cookies&#39;][&#39;kl&#39;] = eng_region # &#39;ar-es&#39;</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">return</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;lang_region&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span> <span class="c1"># type: ignore</span>
+ <span class="n">sxng_locale</span><span class="p">,</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">default</span><span class="p">)</span>
+ <span class="p">)</span></div>
+
+
+
+<span class="n">ddg_reg_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;tw-tzh&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_TW&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;hk-tzh&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_HK&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ct-ca&#39;</span><span class="p">:</span> <span class="s1">&#39;skip&#39;</span><span class="p">,</span> <span class="c1"># ct-ca and es-ca both map to ca_ES</span>
+ <span class="s1">&#39;es-ca&#39;</span><span class="p">:</span> <span class="s1">&#39;ca_ES&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;id-en&#39;</span><span class="p">:</span> <span class="s1">&#39;id_ID&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;no-no&#39;</span><span class="p">:</span> <span class="s1">&#39;nb_NO&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;jp-jp&#39;</span><span class="p">:</span> <span class="s1">&#39;ja_JP&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;kr-kr&#39;</span><span class="p">:</span> <span class="s1">&#39;ko_KR&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;xa-ar&#39;</span><span class="p">:</span> <span class="s1">&#39;ar_SA&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sl-sl&#39;</span><span class="p">:</span> <span class="s1">&#39;sl_SI&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;th-en&#39;</span><span class="p">:</span> <span class="s1">&#39;th_TH&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;vn-en&#39;</span><span class="p">:</span> <span class="s1">&#39;vi_VN&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">ddg_lang_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="c1"># use ar --&gt; ar_EG (Egypt&#39;s arabic)</span>
+ <span class="s2">&quot;ar_DZ&quot;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;ar_JO&quot;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;ar_SA&quot;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use bn --&gt; bn_BD</span>
+ <span class="s1">&#39;bn_IN&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use de --&gt; de_DE</span>
+ <span class="s1">&#39;de_CH&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use en --&gt; en_US,</span>
+ <span class="s1">&#39;en_AU&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;en_CA&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;en_GB&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># Esperanto</span>
+ <span class="s1">&#39;eo_XX&#39;</span><span class="p">:</span> <span class="s1">&#39;eo&#39;</span><span class="p">,</span>
+ <span class="c1"># use es --&gt; es_ES,</span>
+ <span class="s1">&#39;es_AR&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_CL&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_CO&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_CR&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_EC&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_MX&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_PE&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_UY&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_VE&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use fr --&gt; rf_FR</span>
+ <span class="s1">&#39;fr_CA&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fr_CH&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fr_BE&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use nl --&gt; nl_NL</span>
+ <span class="s1">&#39;nl_BE&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># use pt --&gt; pt_PT</span>
+ <span class="s1">&#39;pt_BR&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">,</span>
+ <span class="c1"># skip these languages</span>
+ <span class="s1">&#39;od_IN&#39;</span><span class="p">:</span> <span class="s1">&#39;skip&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;io_XX&#39;</span><span class="p">:</span> <span class="s1">&#39;skip&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;tokipona_XX&#39;</span><span class="p">:</span> <span class="s1">&#39;skip&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+
+<span class="k">def</span> <span class="nf">quote_ddg_bangs</span><span class="p">(</span><span class="n">query</span><span class="p">):</span>
+ <span class="c1"># quote ddg bangs</span>
+ <span class="n">query_parts</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># for val in re.split(r&#39;(\s+)&#39;, query):</span>
+ <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;(\s+)&#39;</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">val</span><span class="o">.</span><span class="n">strip</span><span class="p">():</span>
+ <span class="k">continue</span>
+ <span class="k">if</span> <span class="n">val</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;!&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="n">external_bang</span><span class="o">.</span><span class="n">get_node</span><span class="p">(</span><span class="n">external_bang</span><span class="o">.</span><span class="n">EXTERNAL_BANGS</span><span class="p">,</span> <span class="n">val</span><span class="p">[</span><span class="mi">1</span><span class="p">:]):</span>
+ <span class="n">val</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;&#39;</span><span class="si">{</span><span class="n">val</span><span class="si">}</span><span class="s2">&#39;&quot;</span>
+ <span class="n">query_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
+ <span class="k">return</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">query_parts</span><span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="n">query</span> <span class="o">=</span> <span class="n">quote_ddg_bangs</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">query</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">500</span><span class="p">:</span>
+ <span class="c1"># DDG does not accept queries with more than 499 chars</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">return</span>
+
+ <span class="c1"># Advanced search syntax ends in CAPTCHA</span>
+ <span class="c1"># https://duckduckgo.com/duckduckgo-help-pages/results/syntax/</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
+ <span class="p">[</span>
+ <span class="n">x</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">&quot;site:&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">&quot;intitle:&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">&quot;inurl:&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">removeprefix</span><span class="p">(</span><span class="s2">&quot;filetype:&quot;</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">query</span><span class="o">.</span><span class="n">split</span><span class="p">()</span>
+ <span class="p">]</span>
+ <span class="p">)</span>
+ <span class="n">eng_region</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="k">if</span> <span class="n">eng_region</span> <span class="o">==</span> <span class="s2">&quot;wt-wt&quot;</span><span class="p">:</span>
+ <span class="c1"># https://html.duckduckgo.com/html sets an empty value for &quot;all&quot;.</span>
+ <span class="n">eng_region</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;kl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_region</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;kl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_region</span>
+
+ <span class="c1"># eng_lang = get_ddg_lang(traits, params[&#39;searxng_locale&#39;])</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;POST&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;q&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query</span>
+
+ <span class="c1"># The API is not documented, so we do some reverse engineering and emulate</span>
+ <span class="c1"># what https://html.duckduckgo.com/html does when you press &quot;next Page&quot; link</span>
+ <span class="c1"># again and again ..</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Content-Type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;application/x-www-form-urlencoded&#39;</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Sec-Fetch-Dest&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;document&quot;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Sec-Fetch-Mode&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;navigate&quot;</span> <span class="c1"># at least this one is used by ddg&#39;s bot detection</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Sec-Fetch-Site&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;same-origin&quot;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Sec-Fetch-User&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;?1&quot;</span>
+
+ <span class="c1"># Form of the initial search page does have empty values in the form</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;b&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;df&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;df&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;df&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="mi">2</span><span class="p">:</span>
+
+ <span class="c1"># second page does have an offset of 20</span>
+ <span class="n">offset</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">20</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;s&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">offset</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;dc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span>
+
+ <span class="k">elif</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">2</span><span class="p">:</span>
+
+ <span class="c1"># third and following pages do have an offset of 20 + n*50</span>
+ <span class="n">offset</span> <span class="o">=</span> <span class="mi">20</span> <span class="o">+</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span> <span class="o">*</span> <span class="mi">50</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;s&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">offset</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;dc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">offset</span> <span class="o">+</span> <span class="mi">1</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+
+ <span class="c1"># initial page does not have these additional data in the input form</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;o&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">form_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;o&#39;</span><span class="p">,</span> <span class="s1">&#39;json&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;api&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">form_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;api&#39;</span><span class="p">,</span> <span class="s1">&#39;d.js&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;nextParams&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">form_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;nextParams&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;v&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">form_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;v&#39;</span><span class="p">,</span> <span class="s1">&#39;l&#39;</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Referer&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">url</span>
+
+ <span class="n">vqd</span> <span class="o">=</span> <span class="n">get_vqd</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">eng_region</span><span class="p">,</span> <span class="n">force_request</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
+
+ <span class="c1"># Certain conditions must be met in order to call up one of the</span>
+ <span class="c1"># following pages ...</span>
+
+ <span class="k">if</span> <span class="n">vqd</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;vqd&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">vqd</span> <span class="c1"># follow up pages / requests needs a vqd argument</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="c1"># Don&#39;t try to call follow up pages without a vqd value. DDG</span>
+ <span class="c1"># recognizes this as a request from a bot. This lowers the</span>
+ <span class="c1"># reputation of the SearXNG IP and DDG starts to activate CAPTCHAs.</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">return</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;zh&quot;</span><span class="p">):</span>
+ <span class="c1"># Some locales (at least China) do not have a &quot;next page&quot; button and ddg</span>
+ <span class="c1"># will return a HTTP/2 403 Forbidden for a request of such a page.</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">return</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;param data: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">])</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;param cookies: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">])</span>
+
+
+<div class="viewcode-block" id="is_ddg_captcha">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo.is_ddg_captcha">[docs]</a>
+<span class="k">def</span> <span class="nf">is_ddg_captcha</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;In case of CAPTCHA ddg response its own *not a Robot* dialog and is not</span>
+<span class="sd"> redirected to a CAPTCHA page.&quot;&quot;&quot;</span>
+
+ <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form[@id=&#39;challenge-form&#39;]&quot;</span><span class="p">))</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">303</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">doc</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">is_ddg_captcha</span><span class="p">(</span><span class="n">doc</span><span class="p">):</span>
+ <span class="c1"># set suspend time to zero is OK --&gt; ddg does not block the IP</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">(</span><span class="n">suspended_time</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;CAPTCHA (</span><span class="si">{</span><span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;kl&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
+
+ <span class="n">form</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="s1">&#39;//input[@name=&quot;vqd&quot;]/..&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">form</span><span class="p">):</span>
+ <span class="c1"># some locales (at least China) does not have a &quot;next page&quot; button</span>
+ <span class="n">form</span> <span class="o">=</span> <span class="n">form</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">form_vqd</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">form</span><span class="p">,</span> <span class="s1">&#39;//input[@name=&quot;vqd&quot;]/@value&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+
+ <span class="n">cache_vqd</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;q&#39;</span><span class="p">],</span> <span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;kl&#39;</span><span class="p">],</span> <span class="n">form_vqd</span><span class="p">)</span>
+
+ <span class="c1"># just select &quot;web-result&quot; and ignore results of class &quot;result--ad result--ad--small&quot;</span>
+ <span class="k">for</span> <span class="n">div_result</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="s1">&#39;//div[@id=&quot;links&quot;]/div[contains(@class, &quot;web-result&quot;)]&#39;</span><span class="p">):</span>
+
+ <span class="n">item</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">div_result</span><span class="p">,</span> <span class="s1">&#39;.//h2/a&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">title</span><span class="p">:</span>
+ <span class="c1"># this is the &quot;No results.&quot; item in the result list</span>
+ <span class="k">continue</span>
+ <span class="n">item</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
+ <span class="n">item</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">div_result</span><span class="p">,</span> <span class="s1">&#39;.//h2/a/@href&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">item</span><span class="p">[</span><span class="s2">&quot;content&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">div_result</span><span class="p">,</span> <span class="s1">&#39;.//a[contains(@class, &quot;result__snippet&quot;)]&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">])</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="n">zero_click_info_xpath</span> <span class="o">=</span> <span class="s1">&#39;//div[@id=&quot;zero_click_abstract&quot;]&#39;</span>
+ <span class="n">zero_click</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">doc</span><span class="p">,</span> <span class="n">zero_click_info_xpath</span><span class="p">))</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">if</span> <span class="n">zero_click</span> <span class="ow">and</span> <span class="p">(</span>
+ <span class="s2">&quot;Your IP address is&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">zero_click</span>
+ <span class="ow">and</span> <span class="s2">&quot;Your user agent:&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">zero_click</span>
+ <span class="ow">and</span> <span class="s2">&quot;URL Decoded:&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">zero_click</span>
+ <span class="p">):</span>
+ <span class="n">current_query</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s2">&quot;data&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;q&quot;</span><span class="p">)</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;answer&#39;</span><span class="p">:</span> <span class="n">zero_click</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="s2">&quot;https://duckduckgo.com/?&quot;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s2">&quot;q&quot;</span><span class="p">:</span> <span class="n">current_query</span><span class="p">}),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages &amp; regions from DuckDuckGo.</span>
+
+<span class="sd"> SearXNG&#39;s ``all`` locale maps DuckDuckGo&#39;s &quot;Alle regions&quot; (``wt-wt``).</span>
+<span class="sd"> DuckDuckGo&#39;s language &quot;Browsers preferred language&quot; (``wt_WT``) makes no</span>
+<span class="sd"> sense in a SearXNG request since SearXNG&#39;s ``all`` will not add a</span>
+<span class="sd"> ``Accept-Language`` HTTP header. The value in ``engine_traits.all_locale``</span>
+<span class="sd"> is ``wt-wt`` (the region).</span>
+
+<span class="sd"> Beside regions DuckDuckGo also defines its languages by region codes. By</span>
+<span class="sd"> example these are the english languages in DuckDuckGo:</span>
+
+<span class="sd"> - en_US</span>
+<span class="sd"> - en_AU</span>
+<span class="sd"> - en_CA</span>
+<span class="sd"> - en_GB</span>
+
+<span class="sd"> The function :py:obj:`get_ddg_lang` evaluates DuckDuckGo&#39;s language from</span>
+<span class="sd"> SearXNG&#39;s locale.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=too-many-branches, too-many-statements, disable=import-outside-toplevel</span>
+ <span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">js_variable_to_python</span>
+
+ <span class="c1"># fetch regions</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;wt-wt&#39;</span>
+
+ <span class="c1"># updated from u661.js to u.7669f071a13a7daa57cb / should be updated automatically?</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://duckduckgo.com/dist/util/u.7669f071a13a7daa57cb.js&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from DuckDuckGo is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">js_code</span> <span class="o">=</span> <span class="n">extr</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="s1">&#39;regions:&#39;</span><span class="p">,</span> <span class="s1">&#39;,snippetLengths&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">regions</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">js_code</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">regions</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="o">==</span> <span class="s1">&#39;wt-wt&#39;</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;wt-wt&#39;</span>
+ <span class="k">continue</span>
+
+ <span class="n">region</span> <span class="o">=</span> <span class="n">ddg_reg_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">region</span> <span class="o">==</span> <span class="s1">&#39;skip&#39;</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">region</span><span class="p">:</span>
+ <span class="n">eng_territory</span><span class="p">,</span> <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">eng_tag</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="n">region</span> <span class="o">=</span> <span class="n">eng_lang</span> <span class="o">+</span> <span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">eng_territory</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">region</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) -&gt; </span><span class="si">%s</span><span class="s2"> is unknown by babel&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="n">region</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="c1"># fetch languages</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;lang_region&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="n">js_code</span> <span class="o">=</span> <span class="n">extr</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="s1">&#39;languages:&#39;</span><span class="p">,</span> <span class="s1">&#39;,regions&#39;</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">languages</span> <span class="o">=</span> <span class="n">js_variable_to_python</span><span class="p">(</span><span class="n">js_code</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">eng_lang</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">languages</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+
+ <span class="k">if</span> <span class="n">eng_lang</span> <span class="o">==</span> <span class="s1">&#39;wt_WT&#39;</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="n">babel_tag</span> <span class="o">=</span> <span class="n">ddg_lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_lang</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">babel_tag</span> <span class="o">==</span> <span class="s1">&#39;skip&#39;</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="k">try</span><span class="p">:</span>
+
+ <span class="k">if</span> <span class="n">babel_tag</span> <span class="o">==</span> <span class="s1">&#39;lang_region&#39;</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng_lang</span><span class="p">))</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;lang_region&#39;</span><span class="p">][</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span>
+ <span class="k">continue</span>
+
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">babel_tag</span><span class="p">))</span>
+
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: language </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) is unknown by babel&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/duckduckgo_definitions.html b/_modules/searx/engines/duckduckgo_definitions.html
new file mode 100644
index 000000000..a6ec71485
--- /dev/null
+++ b/_modules/searx/engines/duckduckgo_definitions.html
@@ -0,0 +1,371 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.duckduckgo_definitions &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.duckduckgo_definitions</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.duckduckgo_definitions</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">DuckDuckGo Instant Answer API</span>
+<span class="sd">~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span>
+
+<span class="sd">The `DDG-API &lt;https://duckduckgo.com/api&gt;`__ is no longer documented but from</span>
+<span class="sd">reverse engineering we can see that some services (e.g. instant answers) still</span>
+<span class="sd">in use from the DDG search engine.</span>
+
+<span class="sd">As far we can say the *instant answers* API does not support languages, or at</span>
+<span class="sd">least we could not find out how language support should work. It seems that</span>
+<span class="sd">most of the features are based on English terms.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span><span class="p">,</span> <span class="n">urlparse</span><span class="p">,</span> <span class="n">urljoin</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.data</span> <span class="kn">import</span> <span class="n">WIKIDATA_UNITS</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">html_to_text</span><span class="p">,</span> <span class="n">get_string_replaces_function</span>
+<span class="kn">from</span> <span class="nn">searx.external_urls</span> <span class="kn">import</span> <span class="n">get_external_url</span><span class="p">,</span> <span class="n">get_earth_coordinates_url</span><span class="p">,</span> <span class="n">area_to_osm_zoom</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://duckduckgo.com/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q12805&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://duckduckgo.com/api&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">URL</span> <span class="o">=</span> <span class="s1">&#39;https://api.duckduckgo.com/&#39;</span> <span class="o">+</span> <span class="s1">&#39;?</span><span class="si">{query}</span><span class="s1">&amp;format=json&amp;pretty=0&amp;no_redirect=1&amp;d=1&#39;</span>
+
+<span class="n">WIKIDATA_PREFIX</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;http://www.wikidata.org/entity/&#39;</span><span class="p">,</span> <span class="s1">&#39;https://www.wikidata.org/entity/&#39;</span><span class="p">]</span>
+
+<span class="n">replace_http_by_https</span> <span class="o">=</span> <span class="n">get_string_replaces_function</span><span class="p">({</span><span class="s1">&#39;http:&#39;</span><span class="p">:</span> <span class="s1">&#39;https:&#39;</span><span class="p">})</span>
+
+
+<div class="viewcode-block" id="is_broken_text">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo_definitions.is_broken_text">[docs]</a>
+<span class="k">def</span> <span class="nf">is_broken_text</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;duckduckgo may return something like ``&lt;a href=&quot;xxxx&quot;&gt;http://somewhere Related website&lt;a/&gt;``</span>
+
+<span class="sd"> The href URL is broken, the &quot;Related website&quot; may contains some HTML.</span>
+
+<span class="sd"> The best solution seems to ignore these results.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">return</span> <span class="n">text</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="s1">&#39; &#39;</span> <span class="ow">in</span> <span class="n">text</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">result_to_text</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">htmlResult</span><span class="p">):</span>
+ <span class="c1"># TODO : remove result ending with &quot;Meaning&quot; or &quot;Category&quot; # pylint: disable=fixme</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">htmlResult</span><span class="p">)</span>
+ <span class="n">a</span> <span class="o">=</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//a&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">text</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">is_broken_text</span><span class="p">(</span><span class="n">result</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">result</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">URL</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">}))</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="c1"># pylint: disable=too-many-locals, too-many-branches, too-many-statements</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">search_res</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+
+ <span class="c1"># search_res.get(&#39;Entity&#39;) possible values (not exhaustive) :</span>
+ <span class="c1"># * continent / country / department / location / waterfall</span>
+ <span class="c1"># * actor / musician / artist</span>
+ <span class="c1"># * book / performing art / film / television / media franchise / concert tour / playwright</span>
+ <span class="c1"># * prepared food</span>
+ <span class="c1"># * website / software / os / programming language / file format / software engineer</span>
+ <span class="c1"># * company</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="n">heading</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Heading&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">attributes</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">urls</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">relatedTopics</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># add answer if there is one</span>
+ <span class="n">answer</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Answer&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">answer</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;AnswerType=&quot;</span><span class="si">%s</span><span class="s1">&quot; Answer=&quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;AnswerType&#39;</span><span class="p">),</span> <span class="n">answer</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;AnswerType&#39;</span><span class="p">)</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;calc&#39;</span><span class="p">,</span> <span class="s1">&#39;ip&#39;</span><span class="p">]:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;answer&#39;</span><span class="p">:</span> <span class="n">html_to_text</span><span class="p">(</span><span class="n">answer</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;AbstractURL&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)})</span>
+
+ <span class="c1"># add infobox</span>
+ <span class="k">if</span> <span class="s1">&#39;Definition&#39;</span> <span class="ow">in</span> <span class="n">search_res</span><span class="p">:</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">content</span> <span class="o">+</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Definition&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="s1">&#39;Abstract&#39;</span> <span class="ow">in</span> <span class="n">search_res</span><span class="p">:</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">content</span> <span class="o">+</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Abstract&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+
+ <span class="c1"># image</span>
+ <span class="n">image</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Image&#39;</span><span class="p">)</span>
+ <span class="n">image</span> <span class="o">=</span> <span class="kc">None</span> <span class="k">if</span> <span class="n">image</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span> <span class="k">else</span> <span class="n">image</span>
+ <span class="k">if</span> <span class="n">image</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">urlparse</span><span class="p">(</span><span class="n">image</span><span class="p">)</span><span class="o">.</span><span class="n">netloc</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="n">image</span> <span class="o">=</span> <span class="n">urljoin</span><span class="p">(</span><span class="s1">&#39;https://duckduckgo.com&#39;</span><span class="p">,</span> <span class="n">image</span><span class="p">)</span>
+
+ <span class="c1"># urls</span>
+ <span class="c1"># Official website, Wikipedia page</span>
+ <span class="k">for</span> <span class="n">ddg_result</span> <span class="ow">in</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Results&#39;</span><span class="p">,</span> <span class="p">[]):</span>
+ <span class="n">firstURL</span> <span class="o">=</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;FirstURL&#39;</span><span class="p">)</span>
+ <span class="n">text</span> <span class="o">=</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Text&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">firstURL</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">text</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">text</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">firstURL</span><span class="p">})</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">heading</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">firstURL</span><span class="p">})</span>
+
+ <span class="c1"># related topics</span>
+ <span class="k">for</span> <span class="n">ddg_result</span> <span class="ow">in</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;RelatedTopics&#39;</span><span class="p">,</span> <span class="p">[]):</span>
+ <span class="k">if</span> <span class="s1">&#39;FirstURL&#39;</span> <span class="ow">in</span> <span class="n">ddg_result</span><span class="p">:</span>
+ <span class="n">firstURL</span> <span class="o">=</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;FirstURL&#39;</span><span class="p">)</span>
+ <span class="n">text</span> <span class="o">=</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Text&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">is_broken_text</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
+ <span class="n">suggestion</span> <span class="o">=</span> <span class="n">result_to_text</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Result&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">suggestion</span> <span class="o">!=</span> <span class="n">heading</span> <span class="ow">and</span> <span class="n">suggestion</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">suggestion</span><span class="p">})</span>
+ <span class="k">elif</span> <span class="s1">&#39;Topics&#39;</span> <span class="ow">in</span> <span class="n">ddg_result</span><span class="p">:</span>
+ <span class="n">suggestions</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">relatedTopics</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Name&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">),</span> <span class="s1">&#39;suggestions&#39;</span><span class="p">:</span> <span class="n">suggestions</span><span class="p">})</span>
+ <span class="k">for</span> <span class="n">topic_result</span> <span class="ow">in</span> <span class="n">ddg_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Topics&#39;</span><span class="p">,</span> <span class="p">[]):</span>
+ <span class="n">suggestion</span> <span class="o">=</span> <span class="n">result_to_text</span><span class="p">(</span><span class="n">topic_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Text&#39;</span><span class="p">),</span> <span class="n">topic_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Result&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">suggestion</span> <span class="o">!=</span> <span class="n">heading</span> <span class="ow">and</span> <span class="n">suggestion</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">suggestions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)</span>
+
+ <span class="c1"># abstract</span>
+ <span class="n">abstractURL</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;AbstractURL&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">abstractURL</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="c1"># add as result ? problem always in english</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">abstractURL</span>
+ <span class="n">urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;AbstractSource&#39;</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">abstractURL</span><span class="p">,</span> <span class="s1">&#39;official&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">})</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">abstractURL</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">heading</span><span class="p">})</span>
+
+ <span class="c1"># definition</span>
+ <span class="n">definitionURL</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;DefinitionURL&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">definitionURL</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="c1"># add as result ? as answer ? problem always in english</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">definitionURL</span>
+ <span class="n">urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;DefinitionSource&#39;</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">definitionURL</span><span class="p">})</span>
+
+ <span class="c1"># to merge with wikidata&#39;s infobox</span>
+ <span class="k">if</span> <span class="n">infobox_id</span><span class="p">:</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">replace_http_by_https</span><span class="p">(</span><span class="n">infobox_id</span><span class="p">)</span>
+
+ <span class="c1"># attributes</span>
+ <span class="c1"># some will be converted to urls</span>
+ <span class="k">if</span> <span class="s1">&#39;Infobox&#39;</span> <span class="ow">in</span> <span class="n">search_res</span><span class="p">:</span>
+ <span class="n">infobox</span> <span class="o">=</span> <span class="n">search_res</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;Infobox&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="s1">&#39;content&#39;</span> <span class="ow">in</span> <span class="n">infobox</span><span class="p">:</span>
+ <span class="n">osm_zoom</span> <span class="o">=</span> <span class="mi">17</span>
+ <span class="n">coordinates</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">for</span> <span class="n">info</span> <span class="ow">in</span> <span class="n">infobox</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;content&#39;</span><span class="p">):</span>
+ <span class="n">data_type</span> <span class="o">=</span> <span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;data_type&#39;</span><span class="p">)</span>
+ <span class="n">data_label</span> <span class="o">=</span> <span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;label&#39;</span><span class="p">)</span>
+ <span class="n">data_value</span> <span class="o">=</span> <span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">)</span>
+
+ <span class="c1"># Workaround: ddg may return a double quote</span>
+ <span class="k">if</span> <span class="n">data_value</span> <span class="o">==</span> <span class="s1">&#39;&quot;&quot;&#39;</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="c1"># Is it an external URL ?</span>
+ <span class="c1"># * imdb_id / facebook_profile / youtube_channel / youtube_video / twitter_profile</span>
+ <span class="c1"># * instagram_profile / rotten_tomatoes / spotify_artist_id / itunes_artist_id / soundcloud_id</span>
+ <span class="c1"># * netflix_id</span>
+ <span class="n">external_url</span> <span class="o">=</span> <span class="n">get_external_url</span><span class="p">(</span><span class="n">data_type</span><span class="p">,</span> <span class="n">data_value</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">external_url</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">data_label</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">external_url</span><span class="p">})</span>
+ <span class="k">elif</span> <span class="n">data_type</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;instance&#39;</span><span class="p">,</span> <span class="s1">&#39;wiki_maps_trigger&#39;</span><span class="p">,</span> <span class="s1">&#39;google_play_artist_id&#39;</span><span class="p">]:</span>
+ <span class="c1"># ignore instance: Wikidata value from &quot;Instance Of&quot; (Qxxxx)</span>
+ <span class="c1"># ignore wiki_maps_trigger: reference to a javascript</span>
+ <span class="c1"># ignore google_play_artist_id: service shutdown</span>
+ <span class="k">pass</span>
+ <span class="k">elif</span> <span class="n">data_type</span> <span class="o">==</span> <span class="s1">&#39;string&#39;</span> <span class="ow">and</span> <span class="n">data_label</span> <span class="o">==</span> <span class="s1">&#39;Website&#39;</span><span class="p">:</span>
+ <span class="c1"># There is already an URL for the website</span>
+ <span class="k">pass</span>
+ <span class="k">elif</span> <span class="n">data_type</span> <span class="o">==</span> <span class="s1">&#39;area&#39;</span><span class="p">:</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;label&#39;</span><span class="p">:</span> <span class="n">data_label</span><span class="p">,</span> <span class="s1">&#39;value&#39;</span><span class="p">:</span> <span class="n">area_to_str</span><span class="p">(</span><span class="n">data_value</span><span class="p">),</span> <span class="s1">&#39;entity&#39;</span><span class="p">:</span> <span class="s1">&#39;P2046&#39;</span><span class="p">})</span>
+ <span class="n">osm_zoom</span> <span class="o">=</span> <span class="n">area_to_osm_zoom</span><span class="p">(</span><span class="n">data_value</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;amount&#39;</span><span class="p">))</span>
+ <span class="k">elif</span> <span class="n">data_type</span> <span class="o">==</span> <span class="s1">&#39;coordinates&#39;</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">data_value</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;globe&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;http://www.wikidata.org/entity/Q2&#39;</span><span class="p">:</span>
+ <span class="c1"># coordinate on Earth</span>
+ <span class="c1"># get the zoom information from the area</span>
+ <span class="n">coordinates</span> <span class="o">=</span> <span class="n">info</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="c1"># coordinate NOT on Earth</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;label&#39;</span><span class="p">:</span> <span class="n">data_label</span><span class="p">,</span> <span class="s1">&#39;value&#39;</span><span class="p">:</span> <span class="n">data_value</span><span class="p">,</span> <span class="s1">&#39;entity&#39;</span><span class="p">:</span> <span class="s1">&#39;P625&#39;</span><span class="p">})</span>
+ <span class="k">elif</span> <span class="n">data_type</span> <span class="o">==</span> <span class="s1">&#39;string&#39;</span><span class="p">:</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;label&#39;</span><span class="p">:</span> <span class="n">data_label</span><span class="p">,</span> <span class="s1">&#39;value&#39;</span><span class="p">:</span> <span class="n">data_value</span><span class="p">})</span>
+
+ <span class="k">if</span> <span class="n">coordinates</span><span class="p">:</span>
+ <span class="n">data_label</span> <span class="o">=</span> <span class="n">coordinates</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;label&#39;</span><span class="p">)</span>
+ <span class="n">data_value</span> <span class="o">=</span> <span class="n">coordinates</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">)</span>
+ <span class="n">latitude</span> <span class="o">=</span> <span class="n">data_value</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;latitude&#39;</span><span class="p">)</span>
+ <span class="n">longitude</span> <span class="o">=</span> <span class="n">data_value</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;longitude&#39;</span><span class="p">)</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">get_earth_coordinates_url</span><span class="p">(</span><span class="n">latitude</span><span class="p">,</span> <span class="n">longitude</span><span class="p">,</span> <span class="n">osm_zoom</span><span class="p">)</span>
+ <span class="n">urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="s1">&#39;OpenStreetMap&#39;</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;entity&#39;</span><span class="p">:</span> <span class="s1">&#39;P625&#39;</span><span class="p">})</span>
+
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">heading</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="c1"># TODO get infobox.meta.value where .label=&#39;article_title&#39; # pylint: disable=fixme</span>
+ <span class="k">if</span> <span class="n">image</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">attributes</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">urls</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">relatedTopics</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">urls</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;url&#39;</span><span class="p">],</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">heading</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">})</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;infobox&#39;</span><span class="p">:</span> <span class="n">heading</span><span class="p">,</span>
+ <span class="s1">&#39;id&#39;</span><span class="p">:</span> <span class="n">infobox_id</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">image</span><span class="p">,</span>
+ <span class="s1">&#39;attributes&#39;</span><span class="p">:</span> <span class="n">attributes</span><span class="p">,</span>
+ <span class="s1">&#39;urls&#39;</span><span class="p">:</span> <span class="n">urls</span><span class="p">,</span>
+ <span class="s1">&#39;relatedTopics&#39;</span><span class="p">:</span> <span class="n">relatedTopics</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="k">def</span> <span class="nf">unit_to_str</span><span class="p">(</span><span class="n">unit</span><span class="p">):</span>
+ <span class="k">for</span> <span class="n">prefix</span> <span class="ow">in</span> <span class="n">WIKIDATA_PREFIX</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">unit</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">prefix</span><span class="p">):</span>
+ <span class="n">wikidata_entity</span> <span class="o">=</span> <span class="n">unit</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span> <span class="p">:]</span>
+ <span class="n">real_unit</span> <span class="o">=</span> <span class="n">WIKIDATA_UNITS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">wikidata_entity</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">real_unit</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">unit</span>
+ <span class="k">return</span> <span class="n">real_unit</span><span class="p">[</span><span class="s1">&#39;symbol&#39;</span><span class="p">]</span>
+ <span class="k">return</span> <span class="n">unit</span>
+
+
+<div class="viewcode-block" id="area_to_str">
+<a class="viewcode-back" href="../../../dev/engines/online/duckduckgo.html#searx.engines.duckduckgo_definitions.area_to_str">[docs]</a>
+<span class="k">def</span> <span class="nf">area_to_str</span><span class="p">(</span><span class="n">area</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;parse ``{&#39;unit&#39;: &#39;https://www.wikidata.org/entity/Q712226&#39;, &#39;amount&#39;: &#39;+20.99&#39;}``&quot;&quot;&quot;</span>
+ <span class="n">unit</span> <span class="o">=</span> <span class="n">unit_to_str</span><span class="p">(</span><span class="n">area</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;unit&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">unit</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">amount</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">area</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;amount&#39;</span><span class="p">))</span>
+ <span class="k">return</span> <span class="s1">&#39;</span><span class="si">{}</span><span class="s1"> </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">amount</span><span class="p">,</span> <span class="n">unit</span><span class="p">)</span>
+ <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
+ <span class="k">pass</span>
+ <span class="k">return</span> <span class="s1">&#39;</span><span class="si">{}</span><span class="s1"> </span><span class="si">{}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">area</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;amount&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">),</span> <span class="n">area</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;unit&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/google.html b/_modules/searx/engines/google.html
new file mode 100644
index 000000000..587074dc6
--- /dev/null
+++ b/_modules/searx/engines/google.html
@@ -0,0 +1,618 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.google &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.google</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.google</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Google WEB engine. Some of this</span>
+<span class="sd">implementations (manly the :py:obj:`get_google_info`) are shared by other</span>
+<span class="sd">engines:</span>
+
+<span class="sd">- :ref:`google images engine`</span>
+<span class="sd">- :ref:`google news engine`</span>
+<span class="sd">- :ref:`google videos engine`</span>
+<span class="sd">- :ref:`google scholar engine`</span>
+<span class="sd">- :ref:`google autocomplete`</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+<span class="kn">import</span> <span class="nn">babel.core</span>
+<span class="kn">import</span> <span class="nn">babel.languages</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">,</span> <span class="n">eval_xpath_getindex</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span><span class="p">,</span> <span class="n">region_tag</span><span class="p">,</span> <span class="n">get_official_locales</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineCaptchaException</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.google.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q9366&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developers.google.com/custom-search/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">50</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span> <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;m&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="s1">&#39;y&#39;</span><span class="p">}</span>
+
+<span class="c1"># Filter results. 0: None, 1: Moderate, 2: Strict</span>
+<span class="n">filter_mapping</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;off&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;medium&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;high&#39;</span><span class="p">}</span>
+
+<span class="c1"># specific xpath variables</span>
+<span class="c1"># ------------------------</span>
+
+<span class="c1"># Suggestions are links placed in a *card-section*, we extract only the text</span>
+<span class="c1"># from the links not the links itself.</span>
+<span class="n">suggestion_xpath</span> <span class="o">=</span> <span class="s1">&#39;//div[contains(@class, &quot;EIaa9b&quot;)]//a&#39;</span>
+
+<span class="c1"># UI_ASYNC = &#39;use_ac:true,_fmt:html&#39; # returns a HTTP 500 when user search for</span>
+<span class="c1"># # celebrities like &#39;!google natasha allegri&#39;</span>
+<span class="c1"># # or &#39;!google chris evans&#39;</span>
+<span class="n">UI_ASYNC</span> <span class="o">=</span> <span class="s1">&#39;use_ac:true,_fmt:prog&#39;</span>
+<span class="sd">&quot;&quot;&quot;Format of the response from UI&#39;s async request.&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="get_google_info">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google.get_google_info">[docs]</a>
+<span class="k">def</span> <span class="nf">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">eng_traits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Composing various (language) properties for the google engines (:ref:`google</span>
+<span class="sd"> API`).</span>
+
+<span class="sd"> This function is called by the various google engines (:ref:`google web</span>
+<span class="sd"> engine`, :ref:`google images engine`, :ref:`google news engine` and</span>
+<span class="sd"> :ref:`google videos engine`).</span>
+
+<span class="sd"> :param dict param: Request parameters of the engine. At least</span>
+<span class="sd"> a ``searxng_locale`` key should be in the dictionary.</span>
+
+<span class="sd"> :param eng_traits: Engine&#39;s traits fetched from google preferences</span>
+<span class="sd"> (:py:obj:`searx.enginelib.traits.EngineTraits`)</span>
+
+<span class="sd"> :rtype: dict</span>
+<span class="sd"> :returns:</span>
+<span class="sd"> Py-Dictionary with the key/value pairs:</span>
+
+<span class="sd"> language:</span>
+<span class="sd"> The language code that is used by google (e.g. ``lang_en`` or</span>
+<span class="sd"> ``lang_zh-TW``)</span>
+
+<span class="sd"> country:</span>
+<span class="sd"> The country code that is used by google (e.g. ``US`` or ``TW``)</span>
+
+<span class="sd"> locale:</span>
+<span class="sd"> A instance of :py:obj:`babel.core.Locale` build from the</span>
+<span class="sd"> ``searxng_locale`` value.</span>
+
+<span class="sd"> subdomain:</span>
+<span class="sd"> Google subdomain :py:obj:`google_domains` that fits to the country</span>
+<span class="sd"> code.</span>
+
+<span class="sd"> params:</span>
+<span class="sd"> Py-Dictionary with additional request arguments (can be passed to</span>
+<span class="sd"> :py:func:`urllib.parse.urlencode`).</span>
+
+<span class="sd"> - ``hl`` parameter: specifies the interface language of user interface.</span>
+<span class="sd"> - ``lr`` parameter: restricts search results to documents written in</span>
+<span class="sd"> a particular language.</span>
+<span class="sd"> - ``cr`` parameter: restricts search results to documents</span>
+<span class="sd"> originating in a particular country.</span>
+<span class="sd"> - ``ie`` parameter: sets the character encoding scheme that should</span>
+<span class="sd"> be used to interpret the query string (&#39;utf8&#39;).</span>
+<span class="sd"> - ``oe`` parameter: sets the character encoding scheme that should</span>
+<span class="sd"> be used to decode the XML result (&#39;utf8&#39;).</span>
+
+<span class="sd"> headers:</span>
+<span class="sd"> Py-Dictionary with additional HTTP headers (can be passed to</span>
+<span class="sd"> request&#39;s headers)</span>
+
+<span class="sd"> - ``Accept: &#39;*/*``</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">ret_val</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;language&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;country&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;subdomain&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;params&#39;</span><span class="p">:</span> <span class="p">{},</span>
+ <span class="s1">&#39;headers&#39;</span><span class="p">:</span> <span class="p">{},</span>
+ <span class="s1">&#39;cookies&#39;</span><span class="p">:</span> <span class="p">{},</span>
+ <span class="s1">&#39;locale&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">sxng_locale</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">,</span> <span class="s1">&#39;all&#39;</span><span class="p">)</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">core</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="kc">None</span>
+
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="s1">&#39;lang_en&#39;</span><span class="p">)</span>
+ <span class="n">lang_code</span> <span class="o">=</span> <span class="n">eng_lang</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># lang_zh-TW --&gt; zh-TW / lang_en --&gt; en</span>
+ <span class="n">country</span> <span class="o">=</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span>
+
+ <span class="c1"># Test zh_hans &amp; zh_hant --&gt; in the topmost links in the result list of list</span>
+ <span class="c1"># TW and HK you should a find wiktionary.org zh_hant link. In the result</span>
+ <span class="c1"># list of zh-CN should not be no hant link instead you should find</span>
+ <span class="c1"># zh.m.wikipedia.org/zh somewhere in the top.</span>
+
+ <span class="c1"># &#39;!go 日 :zh-TW&#39; --&gt; https://zh.m.wiktionary.org/zh-hant/%E6%97%A5</span>
+ <span class="c1"># &#39;!go 日 :zh-CN&#39; --&gt; https://zh.m.wikipedia.org/zh/%E6%97%A5</span>
+
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;country&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">country</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;locale&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">locale</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;supported_domains&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">country</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="s1">&#39;www.google.com&#39;</span><span class="p">)</span>
+
+ <span class="c1"># hl parameter:</span>
+ <span class="c1"># The hl parameter specifies the interface language (host language) of</span>
+ <span class="c1"># your user interface. To improve the performance and the quality of your</span>
+ <span class="c1"># search results, you are strongly encouraged to set this parameter</span>
+ <span class="c1"># explicitly.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#hlsp</span>
+ <span class="c1"># The Interface Language:</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results_appendices#interfaceLanguages</span>
+
+ <span class="c1"># https://github.com/searxng/searxng/issues/2515#issuecomment-1607150817</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">lang_code</span><span class="si">}</span><span class="s1">-</span><span class="si">{</span><span class="n">country</span><span class="si">}</span><span class="s1">&#39;</span>
+
+ <span class="c1"># lr parameter:</span>
+ <span class="c1"># The lr (language restrict) parameter restricts search results to</span>
+ <span class="c1"># documents written in a particular language.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#lrsp</span>
+ <span class="c1"># Language Collection Values:</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results_appendices#languageCollections</span>
+ <span class="c1">#</span>
+ <span class="c1"># To select &#39;all&#39; languages an empty &#39;lr&#39; value is used.</span>
+ <span class="c1">#</span>
+ <span class="c1"># Different to other google services, Google Scholar supports to select more</span>
+ <span class="c1"># than one language. The languages are separated by a pipe &#39;|&#39; (logical OR).</span>
+ <span class="c1"># By example: &amp;lr=lang_zh-TW%7Clang_de selects articles written in</span>
+ <span class="c1"># traditional chinese OR german language.</span>
+
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;lr&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span>
+ <span class="k">if</span> <span class="n">sxng_locale</span> <span class="o">==</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;lr&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+
+ <span class="c1"># cr parameter:</span>
+ <span class="c1"># The cr parameter restricts search results to documents originating in a</span>
+ <span class="c1"># particular country.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#crsp</span>
+
+ <span class="c1"># specify a region (country) only if a region is given in the selected</span>
+ <span class="c1"># locale --&gt; https://github.com/searxng/searxng/issues/2672</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;cr&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sxng_locale</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;cr&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;country&#39;</span> <span class="o">+</span> <span class="n">country</span>
+
+ <span class="c1"># gl parameter: (mandatory by Google News)</span>
+ <span class="c1"># The gl parameter value is a two-letter country code. For WebSearch</span>
+ <span class="c1"># results, the gl parameter boosts search results whose country of origin</span>
+ <span class="c1"># matches the parameter value. See the Country Codes section for a list of</span>
+ <span class="c1"># valid values.</span>
+ <span class="c1"># Specifying a gl parameter value in WebSearch requests should improve the</span>
+ <span class="c1"># relevance of results. This is particularly true for international</span>
+ <span class="c1"># customers and, even more specifically, for customers in English-speaking</span>
+ <span class="c1"># countries other than the United States.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#glsp</span>
+
+ <span class="c1"># https://github.com/searxng/searxng/issues/2515#issuecomment-1606294635</span>
+ <span class="c1"># ret_val[&#39;params&#39;][&#39;gl&#39;] = country</span>
+
+ <span class="c1"># ie parameter:</span>
+ <span class="c1"># The ie parameter sets the character encoding scheme that should be used</span>
+ <span class="c1"># to interpret the query string. The default ie value is latin1.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#iesp</span>
+
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;ie&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;utf8&#39;</span>
+
+ <span class="c1"># oe parameter:</span>
+ <span class="c1"># The oe parameter sets the character encoding scheme that should be used</span>
+ <span class="c1"># to decode the XML result. The default oe value is latin1.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#oesp</span>
+
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;oe&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;utf8&#39;</span>
+
+ <span class="c1"># num parameter:</span>
+ <span class="c1"># The num parameter identifies the number of search results to return.</span>
+ <span class="c1"># The default num value is 10, and the maximum value is 20. If you request</span>
+ <span class="c1"># more than 20 results, only 20 results will be returned.</span>
+ <span class="c1"># https://developers.google.com/custom-search/docs/xml_results#numsp</span>
+
+ <span class="c1"># HINT: seems to have no effect (tested in google WEB &amp; Images)</span>
+ <span class="c1"># ret_val[&#39;params&#39;][&#39;num&#39;] = 20</span>
+
+ <span class="c1"># HTTP headers</span>
+
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Accept&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;*/*&#39;</span>
+
+ <span class="c1"># Cookies</span>
+
+ <span class="c1"># - https://github.com/searxng/searxng/pull/1679#issuecomment-1235432746</span>
+ <span class="c1"># - https://github.com/searxng/searxng/issues/1555</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;CONSENT&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;YES+&quot;</span>
+
+ <span class="k">return</span> <span class="n">ret_val</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">detect_google_sorry</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">host</span> <span class="o">==</span> <span class="s1">&#39;sorry.google.com&#39;</span> <span class="ow">or</span> <span class="n">resp</span><span class="o">.</span><span class="n">url</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;/sorry&#39;</span><span class="p">):</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">()</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Google search request&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=line-too-long</span>
+ <span class="n">offset</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span>
+ <span class="n">google_info</span> <span class="o">=</span> <span class="n">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">traits</span><span class="p">)</span>
+
+ <span class="c1"># https://www.google.de/search?q=corona&amp;hl=de&amp;lr=lang_de&amp;start=0&amp;tbs=qdr%3Ad&amp;safe=medium</span>
+ <span class="n">query_url</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;https://&#39;</span>
+ <span class="o">+</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s1">&#39;/search&#39;</span>
+ <span class="o">+</span> <span class="s2">&quot;?&quot;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="o">**</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;filter&#39;</span><span class="p">:</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;start&#39;</span><span class="p">:</span> <span class="n">offset</span><span class="p">,</span>
+ <span class="c1"># &#39;vet&#39;: &#39;12ahUKEwik3ZbIzfn7AhXMX_EDHbUDBh0QxK8CegQIARAC..i&#39;,</span>
+ <span class="c1"># &#39;ved&#39;: &#39;2ahUKEwik3ZbIzfn7AhXMX_EDHbUDBh0Q_skCegQIARAG&#39;,</span>
+ <span class="c1"># &#39;cs&#39; : 1,</span>
+ <span class="c1"># &#39;sa&#39;: &#39;N&#39;,</span>
+ <span class="c1"># &#39;yv&#39;: 3,</span>
+ <span class="c1"># &#39;prmd&#39;: &#39;vin&#39;,</span>
+ <span class="c1"># &#39;ei&#39;: &#39;GASaY6TxOcy_xc8PtYeY6AE&#39;,</span>
+ <span class="c1"># &#39;sa&#39;: &#39;N&#39;,</span>
+ <span class="c1"># &#39;sstk&#39;: &#39;AcOHfVkD7sWCSAheZi-0tx_09XDO55gTWY0JNq3_V26cNN-c8lfD45aZYPI8s_Bqp8s57AHz5pxchDtAGCA_cikAWSjy9kw3kgg&#39;</span>
+ <span class="c1"># formally known as use_mobile_ui</span>
+ <span class="s1">&#39;asearch&#39;</span><span class="p">:</span> <span class="s1">&#39;arc&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;async&#39;</span><span class="p">:</span> <span class="n">UI_ASYNC</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;tbs&#39;</span><span class="p">:</span> <span class="s1">&#39;qdr:&#39;</span> <span class="o">+</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]})</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;safe&#39;</span><span class="p">:</span> <span class="n">filter_mapping</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]]})</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query_url</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="c1"># =26;[3,&quot;dimg_ZNMiZPCqE4apxc8P3a2tuAQ_137&quot;]a87;data:image/jpeg;base64,/9j/4AAQSkZJRgABA</span>
+<span class="c1"># ...6T+9Nl4cnD+gr9OK8I56/tX3l86nWYw//2Q==26;</span>
+<span class="n">RE_DATA_IMAGE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;&quot;(dimg_[^&quot;]*)&quot;[^;]*;(data:image[^;]*;[^;]*);&#39;</span><span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_data_images</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="n">data_image_map</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">for</span> <span class="n">img_id</span><span class="p">,</span> <span class="n">data_image</span> <span class="ow">in</span> <span class="n">RE_DATA_IMAGE</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="n">dom</span><span class="o">.</span><span class="n">text_content</span><span class="p">()):</span>
+ <span class="n">end_pos</span> <span class="o">=</span> <span class="n">data_image</span><span class="o">.</span><span class="n">rfind</span><span class="p">(</span><span class="s1">&#39;=&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">end_pos</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">data_image</span> <span class="o">=</span> <span class="n">data_image</span><span class="p">[:</span> <span class="n">end_pos</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span>
+ <span class="n">data_image_map</span><span class="p">[</span><span class="n">img_id</span><span class="p">]</span> <span class="o">=</span> <span class="n">data_image</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;data:image objects --&gt; </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="n">data_image_map</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
+ <span class="k">return</span> <span class="n">data_image_map</span>
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from google&#39;s search request&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=too-many-branches, too-many-statements</span>
+ <span class="n">detect_google_sorry</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># convert the text to dom</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">data_image_map</span> <span class="o">=</span> <span class="n">_parse_data_images</span><span class="p">(</span><span class="n">dom</span><span class="p">)</span>
+
+ <span class="c1"># results --&gt; answer</span>
+ <span class="n">answer_list</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;LGOjhe&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">answer_list</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">bubble</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;nnFGuf&quot;]&#39;</span><span class="p">):</span>
+ <span class="n">bubble</span><span class="o">.</span><span class="n">drop_tree</span><span class="p">()</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;answer&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">item</span><span class="p">),</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;../..//a/@href&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="p">[</span><span class="kc">None</span><span class="p">])[</span><span class="mi">0</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="c1"># parse results</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@jscontroller, &quot;SC7lYd&quot;)]&#39;</span><span class="p">):</span>
+ <span class="c1"># pylint: disable=too-many-nested-blocks</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">title_tag</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a/h3[1]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">title_tag</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="c1"># this not one of the common google results *section*</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;ignoring item from the result_xpath list: missing title&#39;</span><span class="p">)</span>
+ <span class="k">continue</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">title_tag</span><span class="p">)</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a[h3]/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">url</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;ignoring item from the result_xpath list: missing url of title &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span> <span class="n">title</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">content_nodes</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@data-sncf, &quot;1&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">content_nodes</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">script</span> <span class="ow">in</span> <span class="n">item</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s2">&quot;.//script&quot;</span><span class="p">):</span>
+ <span class="n">script</span><span class="o">.</span><span class="n">getparent</span><span class="p">()</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">script</span><span class="p">)</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">content_nodes</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">content</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;ignoring item from the result_xpath list: missing content of title &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span> <span class="n">title</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">content_nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//img/@src&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">thumbnail</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">thumbnail</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">thumbnail</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;data:image&#39;</span><span class="p">):</span>
+ <span class="n">img_id</span> <span class="o">=</span> <span class="n">content_nodes</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;.//img/@id&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">img_id</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">data_image_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">img_id</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="kc">None</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span> <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">})</span>
+
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span> <span class="c1"># pylint: disable=broad-except</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">e</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="c1"># parse suggestion</span>
+ <span class="k">for</span> <span class="n">suggestion</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">suggestion_xpath</span><span class="p">):</span>
+ <span class="c1"># append suggestion</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)})</span>
+
+ <span class="c1"># return results</span>
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<span class="c1"># get supported languages from their site</span>
+
+
+<span class="n">skip_countries</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="c1"># official language of google-country not in google-languages</span>
+ <span class="s1">&#39;AL&#39;</span><span class="p">,</span> <span class="c1"># Albanien (sq)</span>
+ <span class="s1">&#39;AZ&#39;</span><span class="p">,</span> <span class="c1"># Aserbaidschan (az)</span>
+ <span class="s1">&#39;BD&#39;</span><span class="p">,</span> <span class="c1"># Bangladesch (bn)</span>
+ <span class="s1">&#39;BN&#39;</span><span class="p">,</span> <span class="c1"># Brunei Darussalam (ms)</span>
+ <span class="s1">&#39;BT&#39;</span><span class="p">,</span> <span class="c1"># Bhutan (dz)</span>
+ <span class="s1">&#39;ET&#39;</span><span class="p">,</span> <span class="c1"># Äthiopien (am)</span>
+ <span class="s1">&#39;GE&#39;</span><span class="p">,</span> <span class="c1"># Georgien (ka, os)</span>
+ <span class="s1">&#39;GL&#39;</span><span class="p">,</span> <span class="c1"># Grönland (kl)</span>
+ <span class="s1">&#39;KH&#39;</span><span class="p">,</span> <span class="c1"># Kambodscha (km)</span>
+ <span class="s1">&#39;LA&#39;</span><span class="p">,</span> <span class="c1"># Laos (lo)</span>
+ <span class="s1">&#39;LK&#39;</span><span class="p">,</span> <span class="c1"># Sri Lanka (si, ta)</span>
+ <span class="s1">&#39;ME&#39;</span><span class="p">,</span> <span class="c1"># Montenegro (sr)</span>
+ <span class="s1">&#39;MK&#39;</span><span class="p">,</span> <span class="c1"># Nordmazedonien (mk, sq)</span>
+ <span class="s1">&#39;MM&#39;</span><span class="p">,</span> <span class="c1"># Myanmar (my)</span>
+ <span class="s1">&#39;MN&#39;</span><span class="p">,</span> <span class="c1"># Mongolei (mn)</span>
+ <span class="s1">&#39;MV&#39;</span><span class="p">,</span> <span class="c1"># Malediven (dv) // dv_MV is unknown by babel</span>
+ <span class="s1">&#39;MY&#39;</span><span class="p">,</span> <span class="c1"># Malaysia (ms)</span>
+ <span class="s1">&#39;NP&#39;</span><span class="p">,</span> <span class="c1"># Nepal (ne)</span>
+ <span class="s1">&#39;TJ&#39;</span><span class="p">,</span> <span class="c1"># Tadschikistan (tg)</span>
+ <span class="s1">&#39;TM&#39;</span><span class="p">,</span> <span class="c1"># Turkmenistan (tk)</span>
+ <span class="s1">&#39;UZ&#39;</span><span class="p">,</span> <span class="c1"># Usbekistan (uz)</span>
+<span class="p">]</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">,</span> <span class="n">add_domains</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages from Google.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel, too-many-branches</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;supported_domains&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://www.google.com/preferences&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Response from Google&#39;s preferences is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
+
+ <span class="c1"># supported language codes</span>
+
+ <span class="n">lang_map</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;no&#39;</span><span class="p">:</span> <span class="s1">&#39;nb&#39;</span><span class="p">}</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//select[@name=&#39;hl&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_lang</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;INFO: google UI language </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) is unknown by babel&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">eng_lang</span><span class="p">,</span> <span class="n">x</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;(&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">strip</span><span class="p">()))</span>
+ <span class="k">continue</span>
+ <span class="n">sxng_lang</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">locale</span><span class="p">)</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_lang</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;lang_&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span>
+
+ <span class="c1"># alias languages</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="s1">&#39;zh&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;lang_zh-CN&#39;</span>
+
+ <span class="c1"># supported region codes</span>
+
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//select[@name=&#39;gl&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">eng_country</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">eng_country</span> <span class="ow">in</span> <span class="n">skip_countries</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="k">if</span> <span class="n">eng_country</span> <span class="o">==</span> <span class="s1">&#39;ZZ&#39;</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;ZZ&#39;</span>
+ <span class="k">continue</span>
+
+ <span class="n">sxng_locales</span> <span class="o">=</span> <span class="n">get_official_locales</span><span class="p">(</span><span class="n">eng_country</span><span class="p">,</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">regional</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">sxng_locales</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t map from google country </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) to a babel region.&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;data-name&#39;</span><span class="p">),</span> <span class="n">eng_country</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="k">for</span> <span class="n">sxng_locale</span> <span class="ow">in</span> <span class="n">sxng_locales</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">region_tag</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">)]</span> <span class="o">=</span> <span class="n">eng_country</span>
+
+ <span class="c1"># alias regions</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="s1">&#39;zh-CN&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;HK&#39;</span>
+
+ <span class="c1"># supported domains</span>
+
+ <span class="k">if</span> <span class="n">add_domains</span><span class="p">:</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://www.google.com/supported_domains&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Response from https://www.google.com/supported_domains is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">domain</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">():</span> <span class="c1"># type: ignore</span>
+ <span class="n">domain</span> <span class="o">=</span> <span class="n">domain</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">domain</span> <span class="ow">or</span> <span class="n">domain</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="s1">&#39;.google.com&#39;</span><span class="p">,</span>
+ <span class="p">]:</span>
+ <span class="k">continue</span>
+ <span class="n">region</span> <span class="o">=</span> <span class="n">domain</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;.&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;supported_domains&#39;</span><span class="p">][</span><span class="n">region</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;www&#39;</span> <span class="o">+</span> <span class="n">domain</span> <span class="c1"># type: ignore</span>
+ <span class="k">if</span> <span class="n">region</span> <span class="o">==</span> <span class="s1">&#39;HK&#39;</span><span class="p">:</span>
+ <span class="c1"># There is no google.cn, we use .com.hk for zh-CN</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;supported_domains&#39;</span><span class="p">][</span><span class="s1">&#39;CN&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;www&#39;</span> <span class="o">+</span> <span class="n">domain</span> <span class="c1"># type: ignore</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/google_images.html b/_modules/searx/engines/google_images.html
new file mode 100644
index 000000000..0f3619503
--- /dev/null
+++ b/_modules/searx/engines/google_images.html
@@ -0,0 +1,241 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.google_images &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.google_images</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.google_images</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Google Images engine using the internal</span>
+<span class="sd">Google API used by the Google Go Android app.</span>
+
+<span class="sd">This internal API offer results in</span>
+
+<span class="sd">- JSON (``_fmt:json``)</span>
+<span class="sd">- Protobuf_ (``_fmt:pb``)</span>
+<span class="sd">- Protobuf_ compressed? (``_fmt:pc``)</span>
+<span class="sd">- HTML (``_fmt:html``)</span>
+<span class="sd">- Protobuf_ encoded in JSON (``_fmt:jspb``).</span>
+
+<span class="sd">.. _Protobuf: https://en.wikipedia.org/wiki/Protocol_Buffers</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">loads</span>
+
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">get_google_info</span><span class="p">,</span>
+ <span class="n">time_range_dict</span><span class="p">,</span>
+ <span class="n">detect_google_sorry</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+ <span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+ <span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://images.google.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q521550&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developers.google.com/custom-search&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;images&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">50</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">filter_mapping</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;images&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;active&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;active&#39;</span><span class="p">}</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_images.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Google-Image search request&quot;&quot;&quot;</span>
+
+ <span class="n">google_info</span> <span class="o">=</span> <span class="n">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">traits</span><span class="p">)</span>
+
+ <span class="n">query_url</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;https://&#39;</span>
+ <span class="o">+</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s1">&#39;/search&#39;</span>
+ <span class="o">+</span> <span class="s1">&#39;?&#39;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span> <span class="s1">&#39;tbm&#39;</span><span class="p">:</span> <span class="s2">&quot;isch&quot;</span><span class="p">,</span> <span class="o">**</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">],</span> <span class="s1">&#39;asearch&#39;</span><span class="p">:</span> <span class="s1">&#39;isch&#39;</span><span class="p">})</span>
+ <span class="c1"># don&#39;t urlencode this because wildly different AND bad results</span>
+ <span class="c1"># pagination uses Zero-based numbering</span>
+ <span class="o">+</span> <span class="sa">f</span><span class="s1">&#39;&amp;async=_fmt:json,p:1,ijn:</span><span class="si">{</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;pageno&quot;</span><span class="p">]</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="si">}</span><span class="s1">&#39;</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;tbs&#39;</span><span class="p">:</span> <span class="s1">&#39;qdr:&#39;</span> <span class="o">+</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]})</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;safe&#39;</span><span class="p">:</span> <span class="n">filter_mapping</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]]})</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query_url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="c1"># this ua will allow getting ~50 results instead of 10. #1641</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;User-Agent&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;NSTN/3.60.474802233.release Dalvik/2.1.0 (Linux; U; Android 12;&#39;</span> <span class="sa">f</span><span class="s1">&#39; </span><span class="si">{</span><span class="n">google_info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;country&quot;</span><span class="p">,</span><span class="w"> </span><span class="s2">&quot;US&quot;</span><span class="p">)</span><span class="si">}</span><span class="s1">) gzip&#39;</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_images.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from google&#39;s search request&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">detect_google_sorry</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="n">json_start</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;{&quot;ischj&quot;:&#39;</span><span class="p">)</span>
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">[</span><span class="n">json_start</span><span class="p">:])</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="s2">&quot;ischj&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;metadata&quot;</span><span class="p">,</span> <span class="p">[]):</span>
+ <span class="n">result_item</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">][</span><span class="s2">&quot;referrer_url&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">][</span><span class="s2">&quot;page_title&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;text_in_grid&quot;</span><span class="p">][</span><span class="s2">&quot;snippet&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;source&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">][</span><span class="s2">&quot;site_title&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;resolution&#39;</span><span class="p">:</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s2">&quot;original_image&quot;</span><span class="p">][</span><span class="s2">&quot;width&quot;</span><span class="p">]</span><span class="si">}</span><span class="s1"> x </span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s2">&quot;original_image&quot;</span><span class="p">][</span><span class="s2">&quot;height&quot;</span><span class="p">]</span><span class="si">}</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;original_image&quot;</span><span class="p">][</span><span class="s2">&quot;url&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail_src&#39;</span><span class="p">:</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;thumbnail&quot;</span><span class="p">][</span><span class="s2">&quot;url&quot;</span><span class="p">],</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">author</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;iptc&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;creator&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">author</span><span class="p">:</span>
+ <span class="n">result_item</span><span class="p">[</span><span class="s1">&#39;author&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">author</span><span class="p">)</span>
+
+ <span class="n">copyright_notice</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;iptc&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;copyright_notice&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">copyright_notice</span><span class="p">:</span>
+ <span class="n">result_item</span><span class="p">[</span><span class="s1">&#39;source&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39; | &#39;</span> <span class="o">+</span> <span class="n">copyright_notice</span>
+
+ <span class="n">freshness_date</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;result&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;freshness_date&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">freshness_date</span><span class="p">:</span>
+ <span class="n">result_item</span><span class="p">[</span><span class="s1">&#39;source&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39; | &#39;</span> <span class="o">+</span> <span class="n">freshness_date</span>
+
+ <span class="n">file_size</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;gsa&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;file_size&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">file_size</span><span class="p">:</span>
+ <span class="n">result_item</span><span class="p">[</span><span class="s1">&#39;source&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39; (</span><span class="si">%s</span><span class="s1">)&#39;</span> <span class="o">%</span> <span class="n">file_size</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">result_item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/google_news.html b/_modules/searx/engines/google_news.html
new file mode 100644
index 000000000..c0a7d1124
--- /dev/null
+++ b/_modules/searx/engines/google_news.html
@@ -0,0 +1,418 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.google_news &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.google_news</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.google_news</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Google News engine.</span>
+
+<span class="sd">Google News has a different region handling compared to Google WEB.</span>
+
+<span class="sd">- the ``ceid`` argument has to be set (:py:obj:`ceid_list`)</span>
+<span class="sd">- the hl_ argument has to be set correctly (and different to Google WEB)</span>
+<span class="sd">- the gl_ argument is mandatory</span>
+
+<span class="sd">If one of this argument is not set correctly, the request is redirected to</span>
+<span class="sd">CONSENT dialog::</span>
+
+<span class="sd"> https://consent.google.com/m?continue=</span>
+
+<span class="sd">The google news API ignores some parameters from the common :ref:`google API`:</span>
+
+<span class="sd">- num_ : the number of search results is ignored / there is no paging all</span>
+<span class="sd"> results for a query term are in the first response.</span>
+<span class="sd">- save_ : is ignored / Google-News results are always *SafeSearch*</span>
+
+<span class="sd">.. _hl: https://developers.google.com/custom-search/docs/xml_results#hlsp</span>
+<span class="sd">.. _gl: https://developers.google.com/custom-search/docs/xml_results#glsp</span>
+<span class="sd">.. _num: https://developers.google.com/custom-search/docs/xml_results#numsp</span>
+<span class="sd">.. _save: https://developers.google.com/custom-search/docs/xml_results#safesp</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">import</span> <span class="nn">base64</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">locales</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="k">as</span> <span class="n">_fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">get_google_info</span><span class="p">,</span>
+ <span class="n">detect_google_sorry</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://news.google.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q12020&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developers.google.com/custom-search&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;news&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">False</span>
+
+<span class="c1"># Google-News results are always *SafeSearch*. Option &#39;safesearch&#39; is set to</span>
+<span class="c1"># False here, otherwise checker will report safesearch-errors::</span>
+<span class="c1">#</span>
+<span class="c1"># safesearch : results are identical for safesearch=0 and safesearch=2</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="c1"># send_accept_language_header = True</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_news.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Google-News search request&quot;&quot;&quot;</span>
+
+ <span class="n">sxng_locale</span> <span class="o">=</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">,</span> <span class="s1">&#39;en-US&#39;</span><span class="p">)</span>
+ <span class="n">ceid</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">get_engine_locale</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ceid&#39;</span><span class="p">],</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;US:en&#39;</span><span class="p">)</span>
+ <span class="n">google_info</span> <span class="o">=</span> <span class="n">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">traits</span><span class="p">)</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;news.google.com&#39;</span> <span class="c1"># google news has only one domain</span>
+
+ <span class="n">ceid_region</span><span class="p">,</span> <span class="n">ceid_lang</span> <span class="o">=</span> <span class="n">ceid</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;:&#39;</span><span class="p">)</span>
+ <span class="n">ceid_lang</span><span class="p">,</span> <span class="n">ceid_suffix</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">ceid_lang</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="o">+</span> <span class="p">[</span>
+ <span class="kc">None</span><span class="p">,</span>
+ <span class="p">]</span>
+ <span class="p">)[:</span><span class="mi">2</span><span class="p">]</span>
+
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_lang</span>
+
+ <span class="k">if</span> <span class="n">ceid_suffix</span> <span class="ow">and</span> <span class="n">ceid_suffix</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;Hans&#39;</span><span class="p">,</span> <span class="s1">&#39;Hant&#39;</span><span class="p">]:</span>
+
+ <span class="k">if</span> <span class="n">ceid_region</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="n">ceid_lang</span><span class="p">:</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_lang</span> <span class="o">+</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">ceid_region</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_lang</span> <span class="o">+</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">ceid_suffix</span>
+
+ <span class="k">elif</span> <span class="n">ceid_region</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">!=</span> <span class="n">ceid_lang</span><span class="p">:</span>
+
+ <span class="k">if</span> <span class="n">ceid_region</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;AT&#39;</span><span class="p">,</span> <span class="s1">&#39;BE&#39;</span><span class="p">,</span> <span class="s1">&#39;CH&#39;</span><span class="p">,</span> <span class="s1">&#39;IL&#39;</span><span class="p">,</span> <span class="s1">&#39;SA&#39;</span><span class="p">,</span> <span class="s1">&#39;IN&#39;</span><span class="p">,</span> <span class="s1">&#39;BD&#39;</span><span class="p">,</span> <span class="s1">&#39;PT&#39;</span><span class="p">]:</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_lang</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;hl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_lang</span> <span class="o">+</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">ceid_region</span>
+
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;lr&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;lang_&#39;</span> <span class="o">+</span> <span class="n">ceid_lang</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">][</span><span class="s1">&#39;gl&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ceid_region</span>
+
+ <span class="n">query_url</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;https://&#39;</span>
+ <span class="o">+</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s2">&quot;/search?&quot;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="o">**</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="c1"># ceid includes a &#39;:&#39; character which must not be urlencoded</span>
+ <span class="o">+</span> <span class="p">(</span><span class="s1">&#39;&amp;ceid=</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">ceid</span><span class="p">)</span>
+ <span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query_url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_news.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from google&#39;s search request&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">detect_google_sorry</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="c1"># convert the text to dom</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@class=&quot;xrnccd&quot;]&#39;</span><span class="p">):</span>
+
+ <span class="c1"># The first &lt;a&gt; tag in the &lt;article&gt; contains the link to the article</span>
+ <span class="c1"># The href attribute of the &lt;a&gt; tag is a google internal link, we have</span>
+ <span class="c1"># to decode</span>
+
+ <span class="n">href</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;./article/a/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
+ <span class="n">href</span> <span class="o">=</span> <span class="n">href</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;?&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">href</span> <span class="o">=</span> <span class="n">href</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="n">href</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">urlsafe_b64decode</span><span class="p">(</span><span class="n">href</span> <span class="o">+</span> <span class="s1">&#39;====&#39;</span><span class="p">)</span>
+ <span class="n">href</span> <span class="o">=</span> <span class="n">href</span><span class="p">[</span><span class="n">href</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;http&#39;</span><span class="p">)</span> <span class="p">:]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sa">b</span><span class="s1">&#39;</span><span class="se">\xd2</span><span class="s1">&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">href</span> <span class="o">=</span> <span class="n">href</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;./article/h3[1]&#39;</span><span class="p">))</span>
+
+ <span class="c1"># The pub_date is mostly a string like &#39;yesterday&#39;, not a real</span>
+ <span class="c1"># timezone date or time. Therefore we can&#39;t use publishedDate.</span>
+ <span class="n">pub_date</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;./article//time&#39;</span><span class="p">))</span>
+ <span class="n">pub_origin</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;./article//a[@data-n-tid]&#39;</span><span class="p">))</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="s1">&#39; / &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="n">pub_origin</span><span class="p">,</span> <span class="n">pub_date</span><span class="p">]</span> <span class="k">if</span> <span class="n">x</span><span class="p">])</span>
+
+ <span class="c1"># The image URL is located in a preceding sibling &lt;img&gt; tag, e.g.:</span>
+ <span class="c1"># &quot;https://lh3.googleusercontent.com/DjhQh7DMszk.....z=-p-h100-w100&quot;</span>
+ <span class="c1"># These URL are long but not personalized (double checked via tor).</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;preceding-sibling::a/figure/img/@src&#39;</span><span class="p">))</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">href</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="c1"># return results</span>
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<span class="n">ceid_list</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="s1">&#39;AE:ar&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;AR:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;AT:de&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;AU:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BD:bn&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BE:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BE:nl&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BG:bg&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BR:pt-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;BW:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CA:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CA:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CH:de&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CH:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CL:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CN:zh-Hans&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CO:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CU:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;CZ:cs&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;DE:de&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;EG:ar&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ES:es&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ET:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;FR:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;GB:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;GH:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;GR:el&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;HK:zh-Hant&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;HU:hu&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ID:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ID:id&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IE:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IL:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IL:he&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:bn&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:hi&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:ml&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:mr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:ta&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IN:te&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;IT:it&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;JP:ja&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;KE:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;KR:ko&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;LB:ar&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;LT:lt&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;LV:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;LV:lv&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;MA:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;MX:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;MY:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;NA:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;NG:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;NL:nl&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;NO:no&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;NZ:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;PE:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;PH:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;PK:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;PL:pl&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;PT:pt-150&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;RO:ro&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;RS:sr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;RU:ru&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SA:ar&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SE:sv&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SG:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SI:sl&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SK:sk&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;SN:fr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;TH:th&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;TR:tr&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;TW:zh-Hant&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;TZ:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;UA:ru&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;UA:uk&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;UG:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;US:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;US:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;VE:es-419&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;VN:vi&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ZA:en&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ZW:en&#39;</span><span class="p">,</span>
+<span class="p">]</span>
+<span class="sd">&quot;&quot;&quot;List of region/language combinations supported by Google News. Values of the</span>
+<span class="sd">``ceid`` argument of the Google News REST API.&quot;&quot;&quot;</span>
+
+
+<span class="n">_skip_values</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="s1">&#39;ET:en&#39;</span><span class="p">,</span> <span class="c1"># english (ethiopia)</span>
+ <span class="s1">&#39;ID:en&#39;</span><span class="p">,</span> <span class="c1"># english (indonesia)</span>
+ <span class="s1">&#39;LV:en&#39;</span><span class="p">,</span> <span class="c1"># english (latvia)</span>
+<span class="p">]</span>
+
+<span class="n">_ceid_locale_map</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;NO:no&#39;</span><span class="p">:</span> <span class="s1">&#39;nb-NO&#39;</span><span class="p">}</span>
+
+
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+ <span class="n">_fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">,</span> <span class="n">add_domains</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ceid&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="k">for</span> <span class="n">ceid</span> <span class="ow">in</span> <span class="n">ceid_list</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">ceid</span> <span class="ow">in</span> <span class="n">_skip_values</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="n">region</span><span class="p">,</span> <span class="n">lang</span> <span class="o">=</span> <span class="n">ceid</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;:&#39;</span><span class="p">)</span>
+ <span class="n">x</span> <span class="o">=</span> <span class="n">lang</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">x</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;Hant&#39;</span><span class="p">,</span> <span class="s1">&#39;Hans&#39;</span><span class="p">]:</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+
+ <span class="n">sxng_locale</span> <span class="o">=</span> <span class="n">_ceid_locale_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">ceid</span><span class="p">,</span> <span class="n">lang</span> <span class="o">+</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">region</span><span class="p">)</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: </span><span class="si">%s</span><span class="s2"> -&gt; </span><span class="si">%s</span><span class="s2"> is unknown by babel&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">ceid</span><span class="p">,</span> <span class="n">sxng_locale</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;ceid&#39;</span><span class="p">][</span><span class="n">locales</span><span class="o">.</span><span class="n">region_tag</span><span class="p">(</span><span class="n">locale</span><span class="p">)]</span> <span class="o">=</span> <span class="n">ceid</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/google_scholar.html b/_modules/searx/engines/google_scholar.html
new file mode 100644
index 000000000..3657ffc27
--- /dev/null
+++ b/_modules/searx/engines/google_scholar.html
@@ -0,0 +1,340 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.google_scholar &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.google_scholar</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.google_scholar</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Google Scholar engine.</span>
+
+<span class="sd">Compared to other Google services the Scholar engine has a simple GET REST-API</span>
+<span class="sd">and there does not exists `async` API. Even though the API slightly vintage we</span>
+<span class="sd">can make use of the :ref:`google API` to assemble the arguments of the GET</span>
+<span class="sd">request.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineCaptchaException</span>
+
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">get_google_info</span><span class="p">,</span>
+ <span class="n">time_range_dict</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://scholar.google.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q494817&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developers.google.com/custom-search&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;science&#39;</span><span class="p">,</span> <span class="s1">&#39;scientific publications&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">50</span>
+<span class="n">language_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+
+
+<div class="viewcode-block" id="time_range_args">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_scholar.time_range_args">[docs]</a>
+<span class="k">def</span> <span class="nf">time_range_args</span><span class="p">(</span><span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns a dictionary with a time range arguments based on</span>
+<span class="sd"> ``params[&#39;time_range&#39;]``.</span>
+
+<span class="sd"> Google Scholar supports a detailed search by year. Searching by *last</span>
+<span class="sd"> month* or *last week* (as offered by SearXNG) is uncommon for scientific</span>
+<span class="sd"> publications and is not supported by Google Scholar.</span>
+
+<span class="sd"> To limit the result list when the users selects a range, all the SearXNG</span>
+<span class="sd"> ranges (*day*, *week*, *month*, *year*) are mapped to *year*. If no range</span>
+<span class="sd"> is set an empty dictionary of arguments is returned. Example; when</span>
+<span class="sd"> user selects a time range (current year minus one in 2022):</span>
+
+<span class="sd"> .. code:: python</span>
+
+<span class="sd"> { &#39;as_ylo&#39; : 2021 }</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">ret_val</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">ret_val</span><span class="p">[</span><span class="s1">&#39;as_ylo&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">year</span> <span class="o">-</span> <span class="mi">1</span>
+ <span class="k">return</span> <span class="n">ret_val</span></div>
+
+
+
+<div class="viewcode-block" id="detect_google_captcha">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_scholar.detect_google_captcha">[docs]</a>
+<span class="k">def</span> <span class="nf">detect_google_captcha</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;In case of CAPTCHA Google Scholar open its own *not a Robot* dialog and is</span>
+<span class="sd"> not redirected to ``sorry.google.com``.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//form[@id=&#39;gs_captcha_f&#39;]&quot;</span><span class="p">):</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">()</span></div>
+
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_scholar.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Google-Scholar search request&quot;&quot;&quot;</span>
+
+ <span class="n">google_info</span> <span class="o">=</span> <span class="n">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">traits</span><span class="p">)</span>
+ <span class="c1"># subdomain is: scholar.google.xy</span>
+ <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;www.&quot;</span><span class="p">,</span> <span class="s2">&quot;scholar.&quot;</span><span class="p">)</span>
+
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="o">**</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;start&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="p">,</span>
+ <span class="s1">&#39;as_sdt&#39;</span><span class="p">:</span> <span class="s1">&#39;2007&#39;</span><span class="p">,</span> <span class="c1"># include patents / to disable set &#39;0,5&#39;</span>
+ <span class="s1">&#39;as_vis&#39;</span><span class="p">:</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span> <span class="c1"># include citations / to disable set &#39;1&#39;</span>
+ <span class="p">}</span>
+ <span class="n">args</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">time_range_args</span><span class="p">(</span><span class="n">params</span><span class="p">))</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;https://&#39;</span> <span class="o">+</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span> <span class="o">+</span> <span class="s1">&#39;/scholar?&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="parse_gs_a">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_scholar.parse_gs_a">[docs]</a>
+<span class="k">def</span> <span class="nf">parse_gs_a</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse the text written in green.</span>
+
+<span class="sd"> Possible formats:</span>
+<span class="sd"> * &quot;{authors} - {journal}, {year} - {publisher}&quot;</span>
+<span class="sd"> * &quot;{authors} - {year} - {publisher}&quot;</span>
+<span class="sd"> * &quot;{authors} - {publisher}&quot;</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="n">text</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
+
+ <span class="n">s_text</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39; - &#39;</span><span class="p">)</span>
+ <span class="n">authors</span> <span class="o">=</span> <span class="n">s_text</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;, &#39;</span><span class="p">)</span>
+ <span class="n">publisher</span> <span class="o">=</span> <span class="n">s_text</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">s_text</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">3</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">authors</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="kc">None</span>
+
+ <span class="c1"># the format is &quot;{authors} - {journal}, {year} - {publisher}&quot; or &quot;{authors} - {year} - {publisher}&quot;</span>
+ <span class="c1"># get journal and year</span>
+ <span class="n">journal_year</span> <span class="o">=</span> <span class="n">s_text</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;, &#39;</span><span class="p">)</span>
+ <span class="c1"># journal is optional and may contains some coma</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">journal_year</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">journal</span> <span class="o">=</span> <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">journal_year</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
+ <span class="k">if</span> <span class="n">journal</span> <span class="o">==</span> <span class="s1">&#39;…&#39;</span><span class="p">:</span>
+ <span class="n">journal</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">journal</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="c1"># year</span>
+ <span class="n">year</span> <span class="o">=</span> <span class="n">journal_year</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">publishedDate</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">year</span><span class="o">.</span><span class="n">strip</span><span class="p">(),</span> <span class="s1">&#39;%Y&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
+ <span class="n">publishedDate</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">return</span> <span class="n">authors</span><span class="p">,</span> <span class="n">journal</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">publishedDate</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_scholar.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span> <span class="c1"># pylint: disable=too-many-locals</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse response from Google Scholar&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># convert the text to dom</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">detect_google_captcha</span><span class="p">(</span><span class="n">dom</span><span class="p">)</span>
+
+ <span class="c1"># parse results</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@data-rp]&#39;</span><span class="p">):</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//h3[1]//a&#39;</span><span class="p">))</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">title</span><span class="p">:</span>
+ <span class="c1"># this is a [ZITATION] block</span>
+ <span class="k">continue</span>
+
+ <span class="n">pub_type</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//span[@class=&quot;gs_ctg2&quot;]&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">pub_type</span><span class="p">:</span>
+ <span class="n">pub_type</span> <span class="o">=</span> <span class="n">pub_type</span><span class="p">[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//h3[1]//a/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;gs_rs&quot;]&#39;</span><span class="p">))</span>
+ <span class="n">authors</span><span class="p">,</span> <span class="n">journal</span><span class="p">,</span> <span class="n">publisher</span><span class="p">,</span> <span class="n">publishedDate</span> <span class="o">=</span> <span class="n">parse_gs_a</span><span class="p">(</span>
+ <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;gs_a&quot;]&#39;</span><span class="p">))</span>
+ <span class="p">)</span>
+ <span class="k">if</span> <span class="n">publisher</span> <span class="ow">in</span> <span class="n">url</span><span class="p">:</span>
+ <span class="n">publisher</span> <span class="o">=</span> <span class="kc">None</span>
+
+ <span class="c1"># cited by</span>
+ <span class="n">comments</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;gs_fl&quot;]/a[starts-with(@href,&quot;/scholar?cites=&quot;)]&#39;</span><span class="p">))</span>
+
+ <span class="c1"># link to the html or pdf document</span>
+ <span class="n">html_url</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">pdf_url</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">doc_url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;gs_or_ggsm&quot;]/a/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="n">doc_type</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//span[@class=&quot;gs_ctg2&quot;]&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">doc_type</span> <span class="o">==</span> <span class="s2">&quot;[PDF]&quot;</span><span class="p">:</span>
+ <span class="n">pdf_url</span> <span class="o">=</span> <span class="n">doc_url</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">html_url</span> <span class="o">=</span> <span class="n">doc_url</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;paper.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="n">pub_type</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;authors&#39;</span><span class="p">:</span> <span class="n">authors</span><span class="p">,</span>
+ <span class="s1">&#39;publisher&#39;</span><span class="p">:</span> <span class="n">publisher</span><span class="p">,</span>
+ <span class="s1">&#39;journal&#39;</span><span class="p">:</span> <span class="n">journal</span><span class="p">,</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">publishedDate</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;comments&#39;</span><span class="p">:</span> <span class="n">comments</span><span class="p">,</span>
+ <span class="s1">&#39;html_url&#39;</span><span class="p">:</span> <span class="n">html_url</span><span class="p">,</span>
+ <span class="s1">&#39;pdf_url&#39;</span><span class="p">:</span> <span class="n">pdf_url</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="c1"># parse suggestion</span>
+ <span class="k">for</span> <span class="n">suggestion</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;gs_qsuggest_wrap&quot;)]//li//a&#39;</span><span class="p">):</span>
+ <span class="c1"># append suggestion</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)})</span>
+
+ <span class="k">for</span> <span class="n">correction</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@class=&quot;gs_r gs_pda&quot;]/a&#39;</span><span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;correction&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">correction</span><span class="p">)})</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/google_videos.html b/_modules/searx/engines/google_videos.html
new file mode 100644
index 000000000..066000b5d
--- /dev/null
+++ b/_modules/searx/engines/google_videos.html
@@ -0,0 +1,253 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.google_videos &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.google_videos</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.google_videos</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Google Videos engine.</span>
+
+<span class="sd">.. admonition:: Content-Security-Policy (CSP)</span>
+
+<span class="sd"> This engine needs to allow images from the `data URLs`_ (prefixed with the</span>
+<span class="sd"> ``data:`` scheme)::</span>
+
+<span class="sd"> Header set Content-Security-Policy &quot;img-src &#39;self&#39; data: ;&quot;</span>
+
+<span class="sd">.. _data URLs:</span>
+<span class="sd"> https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.google</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">get_google_info</span><span class="p">,</span>
+ <span class="n">time_range_dict</span><span class="p">,</span>
+ <span class="n">filter_mapping</span><span class="p">,</span>
+ <span class="n">suggestion_xpath</span><span class="p">,</span>
+ <span class="n">detect_google_sorry</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">get_embeded_stream_url</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.google.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q219885&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developers.google.com/custom-search&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;videos&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">50</span>
+<span class="n">language_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_videos.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Google-Video search request&quot;&quot;&quot;</span>
+
+ <span class="n">google_info</span> <span class="o">=</span> <span class="n">get_google_info</span><span class="p">(</span><span class="n">params</span><span class="p">,</span> <span class="n">traits</span><span class="p">)</span>
+
+ <span class="n">query_url</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="s1">&#39;https://&#39;</span>
+ <span class="o">+</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;subdomain&#39;</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s1">&#39;/search&#39;</span>
+ <span class="o">+</span> <span class="s2">&quot;?&quot;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;tbm&#39;</span><span class="p">:</span> <span class="s2">&quot;vid&quot;</span><span class="p">,</span>
+ <span class="s1">&#39;start&#39;</span><span class="p">:</span> <span class="mi">10</span> <span class="o">*</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">],</span>
+ <span class="o">**</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;params&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;asearch&#39;</span><span class="p">:</span> <span class="s1">&#39;arc&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;async&#39;</span><span class="p">:</span> <span class="s1">&#39;use_ac:true,_fmt:html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;tbs&#39;</span><span class="p">:</span> <span class="s1">&#39;qdr:&#39;</span> <span class="o">+</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]})</span>
+ <span class="k">if</span> <span class="s1">&#39;safesearch&#39;</span> <span class="ow">in</span> <span class="n">params</span><span class="p">:</span>
+ <span class="n">query_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;safe&#39;</span><span class="p">:</span> <span class="n">filter_mapping</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]]})</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query_url</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">google_info</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/google.html#searx.engines.google_videos.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get response from google&#39;s search request&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">detect_google_sorry</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="c1"># convert the text to dom</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="c1"># parse results</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;g &quot;)]&#39;</span><span class="p">):</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//img/@src&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">thumbnail</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a/h3[1]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">))</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a/h3[1]/../@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
+
+ <span class="n">c_node</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;ITZIwc&quot;)]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">c_node</span><span class="p">)</span>
+ <span class="n">pub_info</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;gqF9jc&quot;)]&#39;</span><span class="p">))</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;author&#39;</span><span class="p">:</span> <span class="n">pub_info</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="s1">&#39;iframe_src&#39;</span><span class="p">:</span> <span class="n">get_embeded_stream_url</span><span class="p">(</span><span class="n">url</span><span class="p">),</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="c1"># parse suggestion</span>
+ <span class="k">for</span> <span class="n">suggestion</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">suggestion_xpath</span><span class="p">):</span>
+ <span class="c1"># append suggestion</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)})</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/mrs.html b/_modules/searx/engines/mrs.html
new file mode 100644
index 000000000..f6b8a2cd4
--- /dev/null
+++ b/_modules/searx/engines/mrs.html
@@ -0,0 +1,181 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.mrs &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.mrs</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.mrs</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Matrix Rooms Search - a fully-featured, standalone, matrix rooms search service.</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The engine has the following mandatory settings:</span>
+
+<span class="sd">- :py:obj:`base_url`</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: MRS</span>
+<span class="sd"> engine: mrs</span>
+<span class="sd"> base_url: https://mrs-host</span>
+<span class="sd"> ...</span>
+
+<span class="sd">Implementation</span>
+<span class="sd">==============</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote_plus</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://matrixrooms.info&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://gitlab.com/etke.cc/mrs/api/-/blob/main/openapi.yml?ref_type=heads&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;social media&#39;</span><span class="p">]</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="n">matrix_url</span> <span class="o">=</span> <span class="s2">&quot;https://matrix.to&quot;</span>
+<span class="n">page_size</span> <span class="o">=</span> <span class="mi">20</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/online/mrs.html#searx.engines.mrs.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;The ``base_url`` must be set in the configuration, if ``base_url`` is not</span>
+<span class="sd"> set, a :py:obj:`ValueError` is raised during initialization.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">base_url</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;engine MRS, base_url is unset&#39;</span><span class="p">)</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">/search/</span><span class="si">{</span><span class="n">quote_plus</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">page_size</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">page_size</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">():</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">matrix_url</span> <span class="o">+</span> <span class="s1">&#39;/#/&#39;</span> <span class="o">+</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;alias&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;topic&#39;</span><span class="p">]</span>
+ <span class="o">+</span> <span class="sa">f</span><span class="s2">&quot; // </span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;members&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2"> members&quot;</span>
+ <span class="o">+</span> <span class="sa">f</span><span class="s2">&quot; // </span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;alias&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="o">+</span> <span class="sa">f</span><span class="s2">&quot; // </span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;server&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;avatar_url&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/mullvad_leta.html b/_modules/searx/engines/mullvad_leta.html
new file mode 100644
index 000000000..fffbe8172
--- /dev/null
+++ b/_modules/searx/engines/mullvad_leta.html
@@ -0,0 +1,327 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.mullvad_leta &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.mullvad_leta</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.mullvad_leta</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+
+<span class="sd">&quot;&quot;&quot;This is the implementation of the Mullvad-Leta meta-search engine.</span>
+
+<span class="sd">This engine **REQUIRES** that searxng operate within a Mullvad VPN</span>
+
+<span class="sd">If using docker, consider using gluetun for easily connecting to the Mullvad</span>
+
+<span class="sd">- https://github.com/qdm12/gluetun</span>
+
+<span class="sd">Otherwise, follow instructions provided by Mullvad for enabling the VPN on Linux</span>
+
+<span class="sd">- https://mullvad.net/en/help/install-mullvad-app-linux</span>
+
+<span class="sd">.. hint::</span>
+
+<span class="sd"> The :py:obj:`EngineTraits` is empty by default. Maintainers have to run</span>
+<span class="sd"> ``make data.traits`` (in the Mullvad VPN / :py:obj:`fetch_traits`) and rebase</span>
+<span class="sd"> the modified JSON file ``searx/data/engine_traits.json`` on every single</span>
+<span class="sd"> update of SearXNG!</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">httpx</span> <span class="kn">import</span> <span class="n">Response</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">region_tag</span><span class="p">,</span> <span class="n">get_official_locales</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineResponseException</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">use_cache</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># non-cache use only has 100 searches per day!</span>
+
+<span class="n">leta_engine</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;google&#39;</span>
+
+<span class="n">search_url</span> <span class="o">=</span> <span class="s2">&quot;https://leta.mullvad.net&quot;</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="n">search_url</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q47008412&#39;</span><span class="p">,</span> <span class="c1"># the Mullvad id - not leta, but related</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://leta.mullvad.net/faq&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">50</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;day&quot;</span><span class="p">:</span> <span class="s2">&quot;d1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;week&quot;</span><span class="p">:</span> <span class="s2">&quot;w1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;month&quot;</span><span class="p">:</span> <span class="s2">&quot;m1&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;year&quot;</span><span class="p">:</span> <span class="s2">&quot;y1&quot;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">available_leta_engines</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="s1">&#39;google&#39;</span><span class="p">,</span> <span class="c1"># first will be default if provided engine is invalid</span>
+ <span class="s1">&#39;brave&#39;</span><span class="p">,</span>
+<span class="p">]</span>
+
+
+<div class="viewcode-block" id="is_vpn_connected">
+<a class="viewcode-back" href="../../../dev/engines/online/mullvad_leta.html#searx.engines.mullvad_leta.is_vpn_connected">[docs]</a>
+<span class="k">def</span> <span class="nf">is_vpn_connected</span><span class="p">(</span><span class="n">dom</span><span class="p">:</span> <span class="n">html</span><span class="o">.</span><span class="n">HtmlElement</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns true if the VPN is connected, False otherwise&quot;&quot;&quot;</span>
+ <span class="n">connected_text</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//main/div/p[1]&#39;</span><span class="p">))</span>
+ <span class="k">return</span> <span class="n">connected_text</span> <span class="o">!=</span> <span class="s1">&#39;You are not connected to Mullvad VPN.&#39;</span></div>
+
+
+
+<div class="viewcode-block" id="assign_headers">
+<a class="viewcode-back" href="../../../dev/engines/online/mullvad_leta.html#searx.engines.mullvad_leta.assign_headers">[docs]</a>
+<span class="k">def</span> <span class="nf">assign_headers</span><span class="p">(</span><span class="n">headers</span><span class="p">:</span> <span class="nb">dict</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assigns the headers to make a request to Mullvad Leta&quot;&quot;&quot;</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Accept&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8&quot;</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Content-Type&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;application/x-www-form-urlencoded&quot;</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Host&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;leta.mullvad.net&quot;</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Origin&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;https://leta.mullvad.net&quot;</span>
+ <span class="k">return</span> <span class="n">headers</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">params</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
+ <span class="n">country</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">,</span> <span class="s1">&#39;all&#39;</span><span class="p">),</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">result_engine</span> <span class="o">=</span> <span class="n">leta_engine</span>
+ <span class="k">if</span> <span class="n">leta_engine</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">available_leta_engines</span><span class="p">:</span>
+ <span class="n">result_engine</span> <span class="o">=</span> <span class="n">available_leta_engines</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span>
+ <span class="s1">&#39;Configured engine &quot;</span><span class="si">%s</span><span class="s1">&quot; not one of the available engines </span><span class="si">%s</span><span class="s1">, defaulting to &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span>
+ <span class="n">leta_engine</span><span class="p">,</span>
+ <span class="n">available_leta_engines</span><span class="p">,</span>
+ <span class="n">result_engine</span><span class="p">,</span>
+ <span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;POST&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;q&quot;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s2">&quot;gl&quot;</span><span class="p">:</span> <span class="n">country</span> <span class="k">if</span> <span class="n">country</span> <span class="ow">is</span> <span class="nb">str</span> <span class="k">else</span> <span class="s1">&#39;&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;engine&#39;</span><span class="p">:</span> <span class="n">result_engine</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="c1"># pylint: disable=undefined-variable</span>
+ <span class="k">if</span> <span class="n">use_cache</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;oc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;on&quot;</span>
+ <span class="c1"># pylint: enable=undefined-variable</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;dateRestrict&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;dateRestrict&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="c1"># Page 1 is n/a, Page 2 is 11, page 3 is 21, ...</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">][</span><span class="s1">&#39;start&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">),</span> <span class="s2">&quot;1&quot;</span><span class="p">])</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+
+ <span class="n">assign_headers</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">])</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">extract_result</span><span class="p">(</span><span class="n">dom_result</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">html</span><span class="o">.</span><span class="n">HtmlElement</span><span class="p">]):</span>
+ <span class="c1"># Infoboxes sometimes appear in the beginning and will have a length of 0</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">dom_result</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span><span class="p">:</span>
+ <span class="p">[</span><span class="n">a_elem</span><span class="p">,</span> <span class="n">h3_elem</span><span class="p">,</span> <span class="n">p_elem</span><span class="p">]</span> <span class="o">=</span> <span class="n">dom_result</span>
+ <span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">dom_result</span><span class="p">)</span> <span class="o">==</span> <span class="mi">4</span><span class="p">:</span>
+ <span class="p">[</span><span class="n">_</span><span class="p">,</span> <span class="n">a_elem</span><span class="p">,</span> <span class="n">h3_elem</span><span class="p">,</span> <span class="n">p_elem</span><span class="p">]</span> <span class="o">=</span> <span class="n">dom_result</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+ <span class="k">return</span> <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">a_elem</span><span class="o">.</span><span class="n">text</span><span class="p">),</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">h3_elem</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">p_elem</span><span class="p">),</span>
+ <span class="p">}</span>
+
+
+<span class="k">def</span> <span class="nf">extract_results</span><span class="p">(</span><span class="n">search_results</span><span class="p">:</span> <span class="n">html</span><span class="o">.</span><span class="n">HtmlElement</span><span class="p">):</span>
+ <span class="k">for</span> <span class="n">search_result</span> <span class="ow">in</span> <span class="n">search_results</span><span class="p">:</span>
+ <span class="n">dom_result</span> <span class="o">=</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">search_result</span><span class="p">,</span> <span class="s1">&#39;div/div/*&#39;</span><span class="p">)</span>
+ <span class="n">result</span> <span class="o">=</span> <span class="n">extract_result</span><span class="p">(</span><span class="n">dom_result</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">result</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">yield</span> <span class="n">result</span>
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/mullvad_leta.html#searx.engines.mullvad_leta.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">:</span> <span class="n">Response</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Checks if connected to Mullvad VPN, then extracts the search results from</span>
+<span class="sd"> the DOM resp: requests response object&quot;&quot;&quot;</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">is_vpn_connected</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="k">raise</span> <span class="n">SearxEngineResponseException</span><span class="p">(</span><span class="s1">&#39;Not connected to Mullvad VPN&#39;</span><span class="p">)</span>
+ <span class="n">search_results</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="s1">&#39;//main/div[2]/div&#39;</span><span class="p">)</span>
+ <span class="k">return</span> <span class="nb">list</span><span class="p">(</span><span class="n">extract_results</span><span class="p">(</span><span class="n">search_results</span><span class="p">))</span></div>
+
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/mullvad_leta.html#searx.engines.mullvad_leta.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and regions from Mullvad-Leta</span>
+
+<span class="sd"> .. warning::</span>
+
+<span class="sd"> Fetching the engine traits also requires a Mullvad VPN connection. If</span>
+<span class="sd"> not connected, then an error message will print and no traits will be</span>
+<span class="sd"> updated.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+ <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">post</span> <span class="k">as</span> <span class="n">http_post</span>
+
+ <span class="c1"># pylint: enable=import-outside-toplevel</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">http_post</span><span class="p">(</span><span class="n">search_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">assign_headers</span><span class="p">({}))</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">resp</span><span class="p">,</span> <span class="n">Response</span><span class="p">):</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: failed to get response from mullvad-leta. Are you connected to the VPN?&quot;</span><span class="p">)</span>
+ <span class="k">return</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from mullvad-leta is not OK. Are you connected to the VPN?&quot;</span><span class="p">)</span>
+ <span class="k">return</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">is_vpn_connected</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;ERROR: Not connected to Mullvad VPN&#39;</span><span class="p">)</span>
+ <span class="k">return</span>
+ <span class="c1"># supported region codes</span>
+ <span class="n">options</span> <span class="o">=</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="o">.</span><span class="n">body</span><span class="p">,</span> <span class="s1">&#39;//main/div/form/div[2]/div/select[1]/option&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">options</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">options</span><span class="p">)</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;ERROR: could not find any results. Are you connected to the VPN?&#39;</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">options</span><span class="p">:</span>
+ <span class="n">eng_country</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+
+ <span class="n">sxng_locales</span> <span class="o">=</span> <span class="n">get_official_locales</span><span class="p">(</span><span class="n">eng_country</span><span class="p">,</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">keys</span><span class="p">(),</span> <span class="n">regional</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">sxng_locales</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span>
+ <span class="s2">&quot;ERROR: can&#39;t map from Mullvad-Leta country </span><span class="si">%s</span><span class="s2"> (</span><span class="si">%s</span><span class="s2">) to a babel region.&quot;</span>
+ <span class="o">%</span> <span class="p">(</span><span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;data-name&#39;</span><span class="p">),</span> <span class="n">eng_country</span><span class="p">)</span>
+ <span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="k">for</span> <span class="n">sxng_locale</span> <span class="ow">in</span> <span class="n">sxng_locales</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">region_tag</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">)]</span> <span class="o">=</span> <span class="n">eng_country</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/odysee.html b/_modules/searx/engines/odysee.html
new file mode 100644
index 000000000..8aa4f773c
--- /dev/null
+++ b/_modules/searx/engines/odysee.html
@@ -0,0 +1,255 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.odysee &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.odysee</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.odysee</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Odysee_ is a decentralized video hosting platform.</span>
+
+<span class="sd">.. _Odysee: https://github.com/OdyseeTeam/odysee-frontend</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">time</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># Engine metadata</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s2">&quot;https://odysee.com/&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s2">&quot;Q102046570&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s2">&quot;JSON&quot;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># Engine configuration</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">results_per_page</span> <span class="o">=</span> <span class="mi">20</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;videos&#39;</span><span class="p">]</span>
+
+<span class="c1"># Search URL (Note: lighthouse.lbry.com/search works too, and may be faster at times)</span>
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;https://lighthouse.odysee.tv/search&quot;</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;day&quot;</span><span class="p">:</span> <span class="s2">&quot;today&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;week&quot;</span><span class="p">:</span> <span class="s2">&quot;thisweek&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;month&quot;</span><span class="p">:</span> <span class="s2">&quot;thismonth&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;year&quot;</span><span class="p">:</span> <span class="s2">&quot;thisyear&quot;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">start_index</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;pageno&quot;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">results_per_page</span>
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;s&quot;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s2">&quot;size&quot;</span><span class="p">:</span> <span class="n">results_per_page</span><span class="p">,</span>
+ <span class="s2">&quot;from&quot;</span><span class="p">:</span> <span class="n">start_index</span><span class="p">,</span>
+ <span class="s2">&quot;include&quot;</span><span class="p">:</span> <span class="s2">&quot;channel,thumbnail_url,title,description,duration,release_time&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;mediaType&quot;</span><span class="p">:</span> <span class="s2">&quot;video&quot;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">lang</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_dict</span><span class="p">:</span>
+ <span class="n">query_params</span><span class="p">[</span><span class="s1">&#39;time_filter&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">time_range_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">?</span><span class="si">{</span><span class="n">urlencode</span><span class="p">(</span><span class="n">query_params</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="c1"># Format the video duration</span>
+<span class="k">def</span> <span class="nf">format_duration</span><span class="p">(</span><span class="n">duration</span><span class="p">):</span>
+ <span class="n">seconds</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">duration</span><span class="p">)</span>
+ <span class="n">length</span> <span class="o">=</span> <span class="n">time</span><span class="o">.</span><span class="n">gmtime</span><span class="p">(</span><span class="n">seconds</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">length</span><span class="o">.</span><span class="n">tm_hour</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%H:%M:%S&quot;</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s2">&quot;%M:%S&quot;</span><span class="p">,</span> <span class="n">length</span><span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="n">data</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">data</span><span class="p">:</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">]</span>
+ <span class="n">claim_id</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;claimId&quot;</span><span class="p">]</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;title&quot;</span><span class="p">]</span>
+ <span class="n">thumbnail_url</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;thumbnail_url&quot;</span><span class="p">]</span>
+ <span class="n">description</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;description&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span>
+ <span class="n">channel</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;channel&quot;</span><span class="p">]</span>
+ <span class="n">release_time</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;release_time&quot;</span><span class="p">]</span>
+ <span class="n">duration</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s2">&quot;duration&quot;</span><span class="p">]</span>
+
+ <span class="n">release_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">release_time</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;T&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span> <span class="s2">&quot;%Y-%m-</span><span class="si">%d</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">formatted_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">utcfromtimestamp</span><span class="p">(</span><span class="n">release_date</span><span class="o">.</span><span class="n">timestamp</span><span class="p">())</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;https://odysee.com/</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">claim_id</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="n">iframe_url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;https://odysee.com/$/embed/</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">:</span><span class="si">{</span><span class="n">claim_id</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="n">odysee_thumbnail</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;https://thumbnails.odycdn.com/optimize/s:390:0/quality:85/plain/</span><span class="si">{</span><span class="n">thumbnail_url</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="n">formatted_duration</span> <span class="o">=</span> <span class="n">format_duration</span><span class="p">(</span><span class="n">duration</span><span class="p">)</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s2">&quot;url&quot;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="n">description</span><span class="p">,</span>
+ <span class="s2">&quot;author&quot;</span><span class="p">:</span> <span class="n">channel</span><span class="p">,</span>
+ <span class="s2">&quot;publishedDate&quot;</span><span class="p">:</span> <span class="n">formatted_date</span><span class="p">,</span>
+ <span class="s2">&quot;length&quot;</span><span class="p">:</span> <span class="n">formatted_duration</span><span class="p">,</span>
+ <span class="s2">&quot;thumbnail&quot;</span><span class="p">:</span> <span class="n">odysee_thumbnail</span><span class="p">,</span>
+ <span class="s2">&quot;iframe_src&quot;</span><span class="p">:</span> <span class="n">iframe_url</span><span class="p">,</span>
+ <span class="s2">&quot;template&quot;</span><span class="p">:</span> <span class="s2">&quot;videos.html&quot;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/odysee.html#searx.engines.odysee.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> Fetch languages from Odysee&#39;s source code.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span>
+ <span class="s1">&#39;https://raw.githubusercontent.com/OdyseeTeam/odysee-frontend/master/ui/constants/supported_browser_languages.js&#39;</span><span class="p">,</span> <span class="c1"># pylint: disable=line-too-long</span>
+ <span class="n">timeout</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t determine languages from Odysee&quot;</span><span class="p">)</span>
+ <span class="k">return</span>
+
+ <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)[</span><span class="mi">1</span><span class="p">:</span><span class="o">-</span><span class="mi">4</span><span class="p">]:</span>
+ <span class="n">lang_tag</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;: &quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;&#39;&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">lang_tag</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;-&quot;</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: </span><span class="si">%s</span><span class="s2"> is unknown by babel&quot;</span> <span class="o">%</span> <span class="n">lang_tag</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">lang_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">lang_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">lang_tag</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/peertube.html b/_modules/searx/engines/peertube.html
new file mode 100644
index 000000000..2cc5e8041
--- /dev/null
+++ b/_modules/searx/engines/peertube.html
@@ -0,0 +1,303 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.peertube &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.peertube</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.peertube</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Peertube and :py:obj:`SepiaSearch &lt;searx.engines.sepiasearch&gt;` do share</span>
+<span class="sd">(more or less) the same REST API and the schema of the JSON result is identical.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+<span class="kn">from</span> <span class="nn">dateutil.parser</span> <span class="kn">import</span> <span class="n">parse</span>
+<span class="kn">from</span> <span class="nn">dateutil.relativedelta</span> <span class="kn">import</span> <span class="n">relativedelta</span>
+
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">html_to_text</span><span class="p">,</span> <span class="n">humanize_number</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="c1"># pylint: disable=line-too-long</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://joinpeertube.org&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q50938515&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://docs.joinpeertube.org/api-rest-reference.html#tag/Search/operation/searchVideos&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;videos&quot;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;https://peer.tube&quot;</span>
+<span class="sd">&quot;&quot;&quot;Base URL of the Peertube instance. A list of instances is available at:</span>
+
+<span class="sd">- https://instances.joinpeertube.org/instances</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_table</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="n">relativedelta</span><span class="p">(),</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="n">relativedelta</span><span class="p">(</span><span class="n">weeks</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="n">relativedelta</span><span class="p">(</span><span class="n">months</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span>
+ <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="n">relativedelta</span><span class="p">(</span><span class="n">years</span><span class="o">=-</span><span class="mi">1</span><span class="p">),</span>
+<span class="p">}</span>
+
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch_table</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;both&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;false&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;false&#39;</span><span class="p">}</span>
+
+
+<span class="k">def</span> <span class="nf">minute_to_hm</span><span class="p">(</span><span class="n">minute</span><span class="p">):</span>
+ <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">minute</span><span class="p">,</span> <span class="nb">int</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;</span><span class="si">%d</span><span class="s2">:</span><span class="si">%02d</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="nb">divmod</span><span class="p">(</span><span class="n">minute</span><span class="p">,</span> <span class="mi">60</span><span class="p">))</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/peertube.html#searx.engines.peertube.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble request for the Peertube API&quot;&quot;&quot;</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">query</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">False</span>
+
+ <span class="c1"># eng_region = traits.get_region(params[&#39;searxng_locale&#39;], &#39;en_US&#39;)</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="kc">None</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">base_url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span>
+ <span class="o">+</span> <span class="s2">&quot;/api/v1/search/videos?&quot;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;search&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;searchTarget&#39;</span><span class="p">:</span> <span class="s1">&#39;search-index&#39;</span><span class="p">,</span> <span class="c1"># Vidiversum</span>
+ <span class="s1">&#39;resultType&#39;</span><span class="p">:</span> <span class="s1">&#39;videos&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;start&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="p">,</span>
+ <span class="s1">&#39;count&#39;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
+ <span class="c1"># -createdAt: sort by date ascending / createdAt: date descending</span>
+ <span class="s1">&#39;sort&#39;</span><span class="p">:</span> <span class="s1">&#39;-match&#39;</span><span class="p">,</span> <span class="c1"># sort by *match descending*</span>
+ <span class="s1">&#39;nsfw&#39;</span><span class="p">:</span> <span class="n">safesearch_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">eng_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;languageOneOf[]=&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;boostLanguages[]=&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_table</span><span class="p">:</span>
+ <span class="n">time</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">date</span><span class="p">()</span> <span class="o">+</span> <span class="n">time_range_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;startDate=&#39;</span> <span class="o">+</span> <span class="n">time</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">video_response</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+
+<div class="viewcode-block" id="video_response">
+<a class="viewcode-back" href="../../../dev/engines/online/peertube.html#searx.engines.peertube.video_response">[docs]</a>
+<span class="k">def</span> <span class="nf">video_response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse video response from SepiaSearch and Peertube instances.&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+
+ <span class="k">if</span> <span class="s1">&#39;data&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]:</span>
+ <span class="n">metadata</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="n">x</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;channel&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;displayName&#39;</span><span class="p">),</span>
+ <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;channel&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;@&#39;</span> <span class="o">+</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;channel&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;host&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tags&#39;</span><span class="p">,</span> <span class="p">[])),</span>
+ <span class="p">]</span>
+ <span class="k">if</span> <span class="n">x</span>
+ <span class="p">]</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">html_to_text</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="s1">&#39;&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;author&#39;</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;account&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;displayName&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;length&#39;</span><span class="p">:</span> <span class="n">minute_to_hm</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;duration&#39;</span><span class="p">)),</span>
+ <span class="s1">&#39;views&#39;</span><span class="p">:</span> <span class="n">humanize_number</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;views&#39;</span><span class="p">]),</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">parse</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;publishedAt&#39;</span><span class="p">]),</span>
+ <span class="s1">&#39;iframe_src&#39;</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;embedUrl&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;thumbnailUrl&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;previewUrl&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;metadata&#39;</span><span class="p">:</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">metadata</span><span class="p">),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/peertube.html#searx.engines.peertube.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages from peertube&#39;s search-index source code.</span>
+
+<span class="sd"> See videoLanguages_ in commit `8ed5c729 - Refactor and redesign client`_</span>
+
+<span class="sd"> .. _8ed5c729 - Refactor and redesign client:</span>
+<span class="sd"> https://framagit.org/framasoft/peertube/search-index/-/commit/8ed5c729</span>
+<span class="sd"> .. _videoLanguages:</span>
+<span class="sd"> https://framagit.org/framasoft/peertube/search-index/-/commit/8ed5c729#3d8747f9a60695c367c70bb64efba8f403721fad_0_291</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span>
+ <span class="s1">&#39;https://framagit.org/framasoft/peertube/search-index/-/raw/master/client/src/components/Filters.vue&#39;</span><span class="p">,</span>
+ <span class="c1"># the response from search-index repository is very slow</span>
+ <span class="n">timeout</span><span class="o">=</span><span class="mi">60</span><span class="p">,</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from peertube is not OK.&quot;</span><span class="p">)</span>
+ <span class="k">return</span>
+
+ <span class="n">js_lang</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;videoLanguages \(\)[^\n]+(.*?)\]&quot;</span><span class="p">,</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="n">re</span><span class="o">.</span><span class="n">DOTALL</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">js_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t determine languages from peertube&quot;</span><span class="p">)</span>
+ <span class="k">return</span>
+
+ <span class="k">for</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">re</span><span class="o">.</span><span class="n">finditer</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\{ id: &#39;([a-z]+)&#39;, label:&quot;</span><span class="p">,</span> <span class="n">js_lang</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)):</span>
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">lang</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="o">==</span> <span class="s1">&#39;oc&#39;</span><span class="p">:</span>
+ <span class="c1"># Occitanis not known by babel, its closest relative is Catalan</span>
+ <span class="c1"># but &#39;ca&#39; is already in the list of engine_traits.languages --&gt;</span>
+ <span class="c1"># &#39;oc&#39; will be ignored.</span>
+ <span class="k">continue</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: </span><span class="si">%s</span><span class="s2"> is unknown by babel&quot;</span> <span class="o">%</span> <span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="s1">&#39;zh_Hans&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;zh&#39;</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="s1">&#39;zh_Hant&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;zh&#39;</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/qwant.html b/_modules/searx/engines/qwant.html
new file mode 100644
index 000000000..b08ad409a
--- /dev/null
+++ b/_modules/searx/engines/qwant.html
@@ -0,0 +1,471 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.qwant &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.qwant</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.qwant</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This engine uses the Qwant API (https://api.qwant.com/v3) to implement Qwant</span>
+<span class="sd">-Web, -News, -Images and -Videos. The API is undocumented but can be reverse</span>
+<span class="sd">engineered by reading the network log of https://www.qwant.com/ queries.</span>
+
+<span class="sd">For Qwant&#39;s *web-search* two alternatives are implemented:</span>
+
+<span class="sd">- ``web``: uses the :py:obj:`api_url` which returns a JSON structure</span>
+<span class="sd">- ``web-lite``: uses the :py:obj:`web_lite_url` which returns a HTML page</span>
+
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The engine has the following additional settings:</span>
+
+<span class="sd">- :py:obj:`qwant_categ`</span>
+
+<span class="sd">This implementation is used by different qwant engines in the :ref:`settings.yml</span>
+<span class="sd">&lt;settings engine&gt;`:</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: qwant</span>
+<span class="sd"> qwant_categ: web-lite # alternatively use &#39;web&#39;</span>
+<span class="sd"> ...</span>
+<span class="sd"> - name: qwant news</span>
+<span class="sd"> qwant_categ: news</span>
+<span class="sd"> ...</span>
+<span class="sd"> - name: qwant images</span>
+<span class="sd"> qwant_categ: images</span>
+<span class="sd"> ...</span>
+<span class="sd"> - name: qwant videos</span>
+<span class="sd"> qwant_categ: videos</span>
+<span class="sd"> ...</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">datetime</span><span class="p">,</span>
+ <span class="n">timedelta</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">loads</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">flask_babel</span> <span class="kn">import</span> <span class="n">gettext</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+<span class="kn">import</span> <span class="nn">lxml</span>
+
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">SearxEngineAPIException</span><span class="p">,</span>
+ <span class="n">SearxEngineTooManyRequestsException</span><span class="p">,</span>
+ <span class="n">SearxEngineCaptchaException</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">raise_for_httperror</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+ <span class="n">get_embeded_stream_url</span><span class="p">,</span>
+<span class="p">)</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.qwant.com/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q14657870&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">5</span>
+<span class="sd">&quot;&quot;&quot;5 pages maximum (``&amp;p=5``): Trying to do more just results in an improper</span>
+<span class="sd">redirect&quot;&quot;&quot;</span>
+
+<span class="n">qwant_categ</span> <span class="o">=</span> <span class="kc">None</span>
+<span class="sd">&quot;&quot;&quot;One of ``web-lite`` (or ``web``), ``news``, ``images`` or ``videos``&quot;&quot;&quot;</span>
+
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="c1"># safe_search_map = {0: &#39;&amp;safesearch=0&#39;, 1: &#39;&amp;safesearch=1&#39;, 2: &#39;&amp;safesearch=2&#39;}</span>
+
+<span class="c1"># fmt: off</span>
+<span class="n">qwant_news_locales</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="s1">&#39;ca_ad&#39;</span><span class="p">,</span> <span class="s1">&#39;ca_es&#39;</span><span class="p">,</span> <span class="s1">&#39;ca_fr&#39;</span><span class="p">,</span> <span class="s1">&#39;co_fr&#39;</span><span class="p">,</span> <span class="s1">&#39;de_at&#39;</span><span class="p">,</span> <span class="s1">&#39;de_ch&#39;</span><span class="p">,</span> <span class="s1">&#39;de_de&#39;</span><span class="p">,</span> <span class="s1">&#39;en_au&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;en_ca&#39;</span><span class="p">,</span> <span class="s1">&#39;en_gb&#39;</span><span class="p">,</span> <span class="s1">&#39;en_ie&#39;</span><span class="p">,</span> <span class="s1">&#39;en_my&#39;</span><span class="p">,</span> <span class="s1">&#39;en_nz&#39;</span><span class="p">,</span> <span class="s1">&#39;en_us&#39;</span><span class="p">,</span> <span class="s1">&#39;es_ad&#39;</span><span class="p">,</span> <span class="s1">&#39;es_ar&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;es_cl&#39;</span><span class="p">,</span> <span class="s1">&#39;es_co&#39;</span><span class="p">,</span> <span class="s1">&#39;es_es&#39;</span><span class="p">,</span> <span class="s1">&#39;es_mx&#39;</span><span class="p">,</span> <span class="s1">&#39;es_pe&#39;</span><span class="p">,</span> <span class="s1">&#39;eu_es&#39;</span><span class="p">,</span> <span class="s1">&#39;eu_fr&#39;</span><span class="p">,</span> <span class="s1">&#39;fc_ca&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fr_ad&#39;</span><span class="p">,</span> <span class="s1">&#39;fr_be&#39;</span><span class="p">,</span> <span class="s1">&#39;fr_ca&#39;</span><span class="p">,</span> <span class="s1">&#39;fr_ch&#39;</span><span class="p">,</span> <span class="s1">&#39;fr_fr&#39;</span><span class="p">,</span> <span class="s1">&#39;it_ch&#39;</span><span class="p">,</span> <span class="s1">&#39;it_it&#39;</span><span class="p">,</span> <span class="s1">&#39;nl_be&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;nl_nl&#39;</span><span class="p">,</span> <span class="s1">&#39;pt_ad&#39;</span><span class="p">,</span> <span class="s1">&#39;pt_pt&#39;</span><span class="p">,</span>
+<span class="p">]</span>
+<span class="c1"># fmt: on</span>
+
+<span class="c1"># search-url</span>
+
+<span class="n">api_url</span> <span class="o">=</span> <span class="s1">&#39;https://api.qwant.com/v3/search/&#39;</span>
+<span class="sd">&quot;&quot;&quot;URL of Qwant&#39;s API (JSON)&quot;&quot;&quot;</span>
+
+<span class="n">web_lite_url</span> <span class="o">=</span> <span class="s1">&#39;https://lite.qwant.com/&#39;</span>
+<span class="sd">&quot;&quot;&quot;URL of Qwant-Lite (HTML)&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/qwant.html#searx.engines.qwant.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Qwant search request&quot;&quot;&quot;</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">query</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+ <span class="n">q_locale</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;searxng_locale&quot;</span><span class="p">],</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;en_US&#39;</span><span class="p">)</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">api_url</span> <span class="o">+</span> <span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">qwant_categ</span><span class="si">}</span><span class="s1">?&#39;</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">}</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;raise_for_httperror&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+
+ <span class="k">if</span> <span class="n">qwant_categ</span> <span class="o">==</span> <span class="s1">&#39;web-lite&#39;</span><span class="p">:</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">web_lite_url</span> <span class="o">+</span> <span class="s1">&#39;?&#39;</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;locale&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">q_locale</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;l&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">q_locale</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;s&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;p&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;raise_for_httperror&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
+
+ <span class="k">elif</span> <span class="n">qwant_categ</span> <span class="o">==</span> <span class="s1">&#39;images&#39;</span><span class="p">:</span>
+
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;locale&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">q_locale</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;count&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">50</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;offset&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">args</span><span class="p">[</span><span class="s1">&#39;count&#39;</span><span class="p">]</span>
+
+ <span class="k">else</span><span class="p">:</span> <span class="c1"># web, news, videos</span>
+
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;locale&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">q_locale</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;count&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;offset&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">args</span><span class="p">[</span><span class="s1">&#39;count&#39;</span><span class="p">]</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">url</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="k">if</span> <span class="n">qwant_categ</span> <span class="o">==</span> <span class="s1">&#39;web-lite&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">parse_web_lite</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">parse_web_api</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+
+<div class="viewcode-block" id="parse_web_lite">
+<a class="viewcode-back" href="../../../dev/engines/online/qwant.html#searx.engines.qwant.parse_web_lite">[docs]</a>
+<span class="k">def</span> <span class="nf">parse_web_lite</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse results from Qwant-Lite&quot;&quot;&quot;</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//section/article&#39;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s2">&quot;./span[contains(@class, &#39;tooltip&#39;)]&quot;</span><span class="p">):</span>
+ <span class="c1"># ignore randomly interspersed advertising adds</span>
+ <span class="k">continue</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s2">&quot;./span[contains(@class, &#39;url partner&#39;)]&quot;</span><span class="p">)),</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;./h2/a&#39;</span><span class="p">)),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;./p&#39;</span><span class="p">)),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<div class="viewcode-block" id="parse_web_api">
+<a class="viewcode-back" href="../../../dev/engines/online/qwant.html#searx.engines.qwant.parse_web_api">[docs]</a>
+<span class="k">def</span> <span class="nf">parse_web_api</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse results from Qwant&#39;s API&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=too-many-locals, too-many-branches, too-many-statements</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># load JSON result</span>
+ <span class="n">search_results</span> <span class="o">=</span> <span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">data</span> <span class="o">=</span> <span class="n">search_results</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;data&#39;</span><span class="p">,</span> <span class="p">{})</span>
+
+ <span class="c1"># check for an API error</span>
+ <span class="k">if</span> <span class="n">search_results</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;status&#39;</span><span class="p">)</span> <span class="o">!=</span> <span class="s1">&#39;success&#39;</span><span class="p">:</span>
+ <span class="n">error_code</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;error_code&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">error_code</span> <span class="o">==</span> <span class="mi">24</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="n">SearxEngineTooManyRequestsException</span><span class="p">()</span>
+ <span class="k">if</span> <span class="n">search_results</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;data&quot;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;error_data&quot;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;captchaUrl&quot;</span><span class="p">)</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">()</span>
+ <span class="n">msg</span> <span class="o">=</span> <span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;unknown&#39;</span><span class="p">]))</span>
+ <span class="k">raise</span> <span class="n">SearxEngineAPIException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">error_code</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
+
+ <span class="c1"># raise for other errors</span>
+ <span class="n">raise_for_httperror</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">qwant_categ</span> <span class="o">==</span> <span class="s1">&#39;web&#39;</span><span class="p">:</span>
+ <span class="c1"># The WEB query contains a list named &#39;mainline&#39;. This list can contain</span>
+ <span class="c1"># different result types (e.g. mainline[0][&#39;type&#39;] returns type of the</span>
+ <span class="c1"># result items in mainline[0][&#39;items&#39;]</span>
+ <span class="n">mainline</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;result&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;mainline&#39;</span><span class="p">,</span> <span class="p">{})</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="c1"># Queries on News, Images and Videos do not have a list named &#39;mainline&#39;</span>
+ <span class="c1"># in the response. The result items are directly in the list</span>
+ <span class="c1"># result[&#39;items&#39;].</span>
+ <span class="n">mainline</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;result&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="n">mainline</span> <span class="o">=</span> <span class="p">[</span>
+ <span class="p">{</span><span class="s1">&#39;type&#39;</span><span class="p">:</span> <span class="n">qwant_categ</span><span class="p">,</span> <span class="s1">&#39;items&#39;</span><span class="p">:</span> <span class="n">mainline</span><span class="p">},</span>
+ <span class="p">]</span>
+
+ <span class="c1"># return empty array if there are no results</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">mainline</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">mainline</span><span class="p">:</span>
+ <span class="n">mainline_type</span> <span class="o">=</span> <span class="n">row</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;type&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">mainline_type</span> <span class="o">!=</span> <span class="n">qwant_categ</span><span class="p">:</span>
+ <span class="k">continue</span>
+
+ <span class="k">if</span> <span class="n">mainline_type</span> <span class="o">==</span> <span class="s1">&#39;ads&#39;</span><span class="p">:</span>
+ <span class="c1"># ignore adds</span>
+ <span class="k">continue</span>
+
+ <span class="n">mainline_items</span> <span class="o">=</span> <span class="n">row</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;items&#39;</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">mainline_items</span><span class="p">:</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;title&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="n">res_url</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;url&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">mainline_type</span> <span class="o">==</span> <span class="s1">&#39;web&#39;</span><span class="p">:</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;desc&#39;</span><span class="p">]</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">res_url</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">elif</span> <span class="n">mainline_type</span> <span class="o">==</span> <span class="s1">&#39;news&#39;</span><span class="p">:</span>
+
+ <span class="n">pub_date</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;date&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">pub_date</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">pub_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">pub_date</span><span class="p">)</span>
+ <span class="n">news_media</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;media&#39;</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">if</span> <span class="n">news_media</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">news_media</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;pict&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;url&#39;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">res_url</span><span class="p">,</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">pub_date</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">elif</span> <span class="n">mainline_type</span> <span class="o">==</span> <span class="s1">&#39;images&#39;</span><span class="p">:</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span>
+ <span class="n">img_src</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;media&#39;</span><span class="p">]</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">res_url</span><span class="p">,</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail_src&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">img_src</span><span class="p">,</span>
+ <span class="s1">&#39;resolution&#39;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s1">&#39;width&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2"> x </span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s1">&#39;height&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
+ <span class="s1">&#39;img_format&#39;</span><span class="p">:</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;thumb_type&#39;</span><span class="p">),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">elif</span> <span class="n">mainline_type</span> <span class="o">==</span> <span class="s1">&#39;videos&#39;</span><span class="p">:</span>
+ <span class="c1"># some videos do not have a description: while qwant-video</span>
+ <span class="c1"># returns an empty string, such video from a qwant-web query</span>
+ <span class="c1"># miss the &#39;desc&#39; key.</span>
+ <span class="n">d</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;desc&#39;</span><span class="p">),</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;source&#39;</span><span class="p">),</span> <span class="n">item</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;channel&#39;</span><span class="p">)</span>
+ <span class="n">content_parts</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">if</span> <span class="n">d</span><span class="p">:</span>
+ <span class="n">content_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">s</span><span class="p">:</span>
+ <span class="n">content_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2"> &quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;Source&quot;</span><span class="p">),</span> <span class="n">s</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">c</span><span class="p">:</span>
+ <span class="n">content_parts</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">: </span><span class="si">%s</span><span class="s2"> &quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;Channel&quot;</span><span class="p">),</span> <span class="n">c</span><span class="p">))</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="s1">&#39; // &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">content_parts</span><span class="p">)</span>
+ <span class="n">length</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;duration&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">length</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">length</span> <span class="o">=</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">milliseconds</span><span class="o">=</span><span class="n">length</span><span class="p">)</span>
+ <span class="n">pub_date</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;date&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">pub_date</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">pub_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">fromtimestamp</span><span class="p">(</span><span class="n">pub_date</span><span class="p">)</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">item</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span>
+ <span class="c1"># from some locations (DE and others?) the s2 link do</span>
+ <span class="c1"># response a &#39;Please wait ..&#39; but does not deliver the thumbnail</span>
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">thumbnail</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;https://s2.qwant.com&#39;</span><span class="p">,</span> <span class="s1">&#39;https://s1.qwant.com&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">res_url</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;iframe_src&#39;</span><span class="p">:</span> <span class="n">get_embeded_stream_url</span><span class="p">(</span><span class="n">res_url</span><span class="p">),</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">pub_date</span><span class="p">,</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">thumbnail</span><span class="p">,</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;videos.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;length&#39;</span><span class="p">:</span> <span class="n">length</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+ <span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">network</span>
+ <span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">region_tag</span>
+ <span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extr</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">network</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">about</span><span class="p">[</span><span class="s1">&#39;website&#39;</span><span class="p">])</span>
+ <span class="n">json_string</span> <span class="o">=</span> <span class="n">extr</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">,</span> <span class="s1">&#39;INITIAL_PROPS = &#39;</span><span class="p">,</span> <span class="s1">&#39;&lt;/script&gt;&#39;</span><span class="p">)</span>
+
+ <span class="n">q_initial_props</span> <span class="o">=</span> <span class="n">loads</span><span class="p">(</span><span class="n">json_string</span><span class="p">)</span>
+ <span class="n">q_locales</span> <span class="o">=</span> <span class="n">q_initial_props</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;locales&#39;</span><span class="p">)</span>
+ <span class="n">eng_tag_list</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+
+ <span class="k">for</span> <span class="n">country</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">q_locales</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="k">for</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">v</span><span class="p">[</span><span class="s1">&#39;langs&#39;</span><span class="p">]:</span>
+ <span class="n">_locale</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">{lang}</span><span class="s2">_</span><span class="si">{country}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">lang</span><span class="o">=</span><span class="n">lang</span><span class="p">,</span> <span class="n">country</span><span class="o">=</span><span class="n">country</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">qwant_categ</span> <span class="o">==</span> <span class="s1">&#39;news&#39;</span> <span class="ow">and</span> <span class="n">_locale</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">qwant_news_locales</span><span class="p">:</span>
+ <span class="c1"># qwant-news does not support all locales from qwant-web:</span>
+ <span class="k">continue</span>
+
+ <span class="n">eng_tag_list</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">_locale</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">eng_tag</span> <span class="ow">in</span> <span class="n">eng_tag_list</span><span class="p">:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;_&#39;</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t determine babel locale of quant&#39;s locale </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/radio_browser.html b/_modules/searx/engines/radio_browser.html
new file mode 100644
index 000000000..feac3ff65
--- /dev/null
+++ b/_modules/searx/engines/radio_browser.html
@@ -0,0 +1,288 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.radio_browser &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.radio_browser</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.radio_browser</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Search radio stations from RadioBrowser by `Advanced station search API`_.</span>
+
+<span class="sd">.. _Advanced station search API:</span>
+<span class="sd"> https://de1.api.radio-browser.info/#Advanced_station_search</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+<span class="kn">from</span> <span class="nn">flask_babel</span> <span class="kn">import</span> <span class="n">gettext</span>
+
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.radio-browser.info/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q111664849&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://de1.api.radio-browser.info/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;music&#39;</span><span class="p">,</span> <span class="s1">&#39;radio&#39;</span><span class="p">]</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;https://de1.api.radio-browser.info&quot;</span> <span class="c1"># see https://api.radio-browser.info/ for all nodes</span>
+<span class="n">number_of_results</span> <span class="o">=</span> <span class="mi">10</span>
+
+<span class="n">station_filters</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># [&#39;countrycode&#39;, &#39;language&#39;]</span>
+<span class="sd">&quot;&quot;&quot;A list of filters to be applied to the search of radio stations. By default</span>
+<span class="sd">none filters are applied. Valid filters are:</span>
+
+<span class="sd">``language``</span>
+<span class="sd"> Filter stations by selected language. For instance the ``de`` from ``:de-AU``</span>
+<span class="sd"> will be translated to `german` and used in the argument ``language=``.</span>
+
+<span class="sd">``countrycode``</span>
+<span class="sd"> Filter stations by selected country. The 2-digit countrycode of the station</span>
+<span class="sd"> comes from the region the user selected. For instance ``:de-AU`` will filter</span>
+<span class="sd"> out all stations not in ``AU``.</span>
+
+<span class="sd">.. note::</span>
+
+<span class="sd"> RadioBrowser has registered a lot of languages and countrycodes unknown to</span>
+<span class="sd"> :py:obj:`babel` and note that when searching for radio stations, users are</span>
+<span class="sd"> more likely to search by name than by region or language.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;name&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;order&#39;</span><span class="p">:</span> <span class="s1">&#39;votes&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;offset&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">number_of_results</span><span class="p">,</span>
+ <span class="s1">&#39;limit&#39;</span><span class="p">:</span> <span class="n">number_of_results</span><span class="p">,</span>
+ <span class="s1">&#39;hidebroken&#39;</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;reverse&#39;</span><span class="p">:</span> <span class="s1">&#39;true&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="k">if</span> <span class="s1">&#39;language&#39;</span> <span class="ow">in</span> <span class="n">station_filters</span><span class="p">:</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">])</span> <span class="c1"># type: ignore</span>
+ <span class="k">if</span> <span class="n">lang</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">lang</span>
+
+ <span class="k">if</span> <span class="s1">&#39;countrycode&#39;</span> <span class="ow">in</span> <span class="n">station_filters</span><span class="p">:</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">countrycode</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
+ <span class="k">if</span> <span class="n">countrycode</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;countrycodes&#39;</span><span class="p">]:</span> <span class="c1"># type: ignore</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;countrycode&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">countrycode</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">/json/stations/search?</span><span class="si">{</span><span class="n">urlencode</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">json_resp</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">json_resp</span><span class="p">:</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;homepage&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">url</span><span class="p">:</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url_resolved&#39;</span><span class="p">]</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">tags</span> <span class="o">=</span> <span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tags&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">tags</span><span class="p">:</span>
+ <span class="n">content</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tags</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">&#39;state&#39;</span><span class="p">,</span> <span class="s1">&#39;country&#39;</span><span class="p">]:</span>
+ <span class="n">v</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">v</span><span class="p">:</span>
+ <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="n">content</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
+
+ <span class="n">metadata</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">codec</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;codec&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">codec</span> <span class="ow">and</span> <span class="n">codec</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">!=</span> <span class="s1">&#39;unknown&#39;</span><span class="p">:</span>
+ <span class="n">metadata</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">codec</span><span class="si">}</span><span class="s1"> &#39;</span> <span class="o">+</span> <span class="n">gettext</span><span class="p">(</span><span class="s1">&#39;radio&#39;</span><span class="p">))</span>
+ <span class="k">for</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="p">(</span><span class="n">gettext</span><span class="p">(</span><span class="s1">&#39;bitrate&#39;</span><span class="p">),</span> <span class="s1">&#39;bitrate&#39;</span><span class="p">),</span>
+ <span class="p">(</span><span class="n">gettext</span><span class="p">(</span><span class="s1">&#39;votes&#39;</span><span class="p">),</span> <span class="s1">&#39;votes&#39;</span><span class="p">),</span>
+ <span class="p">(</span><span class="n">gettext</span><span class="p">(</span><span class="s1">&#39;clicks&#39;</span><span class="p">),</span> <span class="s1">&#39;clickcount&#39;</span><span class="p">),</span>
+ <span class="p">]:</span>
+ <span class="n">v</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">y</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">v</span><span class="p">:</span>
+ <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="n">metadata</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">v</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail&#39;</span><span class="p">:</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;favicon&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;http://&quot;</span><span class="p">,</span> <span class="s2">&quot;https://&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">content</span><span class="p">),</span>
+ <span class="s1">&#39;metadata&#39;</span><span class="p">:</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">metadata</span><span class="p">),</span>
+ <span class="s1">&#39;iframe_src&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;url_resolved&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;http://&quot;</span><span class="p">,</span> <span class="s2">&quot;https://&quot;</span><span class="p">),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/radio_browser.html#searx.engines.radio_browser.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and countrycodes from RadioBrowser</span>
+
+<span class="sd"> - ``traits.languages``: `list of languages API`_</span>
+<span class="sd"> - ``traits.custom[&#39;countrycodes&#39;]``: `list of countries API`_</span>
+
+<span class="sd"> .. _list of countries API: https://de1.api.radio-browser.info/#List_of_countries</span>
+<span class="sd"> .. _list of languages API: https://de1.api.radio-browser.info/#List_of_languages</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+
+ <span class="kn">from</span> <span class="nn">babel.core</span> <span class="kn">import</span> <span class="n">get_global</span>
+
+ <span class="n">babel_reg_list</span> <span class="o">=</span> <span class="n">get_global</span><span class="p">(</span><span class="s2">&quot;territory_languages&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
+
+ <span class="n">language_list</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s1">/json/languages&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">json</span><span class="p">()</span> <span class="c1"># type: ignore</span>
+ <span class="n">country_list</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s1">/json/countries&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">json</span><span class="p">()</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">for</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">language_list</span><span class="p">:</span>
+
+ <span class="n">babel_lang</span> <span class="o">=</span> <span class="n">lang</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;iso_639&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">babel_lang</span><span class="p">:</span>
+ <span class="c1"># the language doesn&#39;t have any iso code, and hence can&#39;t be parsed</span>
+ <span class="c1"># print(f&quot;ERROR: lang - no iso code in {lang}&quot;)</span>
+ <span class="k">continue</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">babel_lang</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s2">&quot;-&quot;</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="c1"># print(f&quot;ERROR: language tag {babel_lang} is unknown by babel&quot;)</span>
+ <span class="k">continue</span>
+
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">lang</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">]</span>
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="n">countrycodes</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+ <span class="k">for</span> <span class="n">region</span> <span class="ow">in</span> <span class="n">country_list</span><span class="p">:</span>
+ <span class="c1"># country_list contains duplicates that differ only in upper/lower case</span>
+ <span class="n">_reg</span> <span class="o">=</span> <span class="n">region</span><span class="p">[</span><span class="s1">&#39;iso_3166_1&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">upper</span><span class="p">()</span>
+ <span class="k">if</span> <span class="n">_reg</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">babel_reg_list</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ERROR: region tag </span><span class="si">{</span><span class="n">region</span><span class="p">[</span><span class="s1">&#39;iso_3166_1&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2"> is unknown by babel&quot;</span><span class="p">)</span>
+ <span class="k">continue</span>
+ <span class="n">countrycodes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">_reg</span><span class="p">)</span>
+
+ <span class="n">countrycodes</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">countrycodes</span><span class="p">)</span>
+ <span class="n">countrycodes</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;countrycodes&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">countrycodes</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/sepiasearch.html b/_modules/searx/engines/sepiasearch.html
new file mode 100644
index 000000000..7c5ac5934
--- /dev/null
+++ b/_modules/searx/engines/sepiasearch.html
@@ -0,0 +1,196 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.sepiasearch &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.sepiasearch</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.sepiasearch</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;SepiaSearch uses the same languages as :py:obj:`Peertube</span>
+<span class="sd">&lt;searx.engines.peertube&gt;` and the response is identical to the response from the</span>
+<span class="sd">peertube engines.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+
+<span class="kn">from</span> <span class="nn">searx.engines.peertube</span> <span class="kn">import</span> <span class="n">fetch_traits</span> <span class="c1"># pylint: disable=unused-import</span>
+<span class="kn">from</span> <span class="nn">searx.engines.peertube</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="c1"># pylint: disable=unused-import</span>
+ <span class="n">video_response</span><span class="p">,</span>
+ <span class="n">safesearch_table</span><span class="p">,</span>
+ <span class="n">time_range_table</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="c1"># pylint: disable=line-too-long</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://sepiasearch.org&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://docs.joinpeertube.org/api-rest-reference.html#tag/Search/operation/searchVideos&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;videos&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://sepiasearch.org&#39;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/peertube.html#searx.engines.sepiasearch.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble request for the SepiaSearch API&quot;&quot;&quot;</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">query</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">False</span>
+
+ <span class="c1"># eng_region = traits.get_region(params[&#39;searxng_locale&#39;], &#39;en_US&#39;)</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="kc">None</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">base_url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s2">&quot;/&quot;</span><span class="p">)</span>
+ <span class="o">+</span> <span class="s2">&quot;/api/v1/search/videos?&quot;</span>
+ <span class="o">+</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;search&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;start&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">10</span><span class="p">,</span>
+ <span class="s1">&#39;count&#39;</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
+ <span class="c1"># -createdAt: sort by date ascending / createdAt: date descending</span>
+ <span class="s1">&#39;sort&#39;</span><span class="p">:</span> <span class="s1">&#39;-match&#39;</span><span class="p">,</span> <span class="c1"># sort by *match descending*</span>
+ <span class="s1">&#39;nsfw&#39;</span><span class="p">:</span> <span class="n">safesearch_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">eng_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;languageOneOf[]=&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;boostLanguages[]=&#39;</span> <span class="o">+</span> <span class="n">eng_lang</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]</span> <span class="ow">in</span> <span class="n">time_range_table</span><span class="p">:</span>
+ <span class="n">time</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span><span class="o">.</span><span class="n">date</span><span class="p">()</span> <span class="o">+</span> <span class="n">time_range_table</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">]]</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">+=</span> <span class="s1">&#39;&amp;startDate=&#39;</span> <span class="o">+</span> <span class="n">time</span><span class="o">.</span><span class="n">isoformat</span><span class="p">()</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">video_response</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/sqlite.html b/_modules/searx/engines/sqlite.html
new file mode 100644
index 000000000..5fcf9daad
--- /dev/null
+++ b/_modules/searx/engines/sqlite.html
@@ -0,0 +1,216 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.sqlite &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.sqlite</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.sqlite</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;SQLite is a small, fast and reliable SQL database engine. It does not require</span>
+<span class="sd">any extra dependency.</span>
+
+<span class="sd">Example</span>
+<span class="sd">=======</span>
+
+<span class="sd">.. _MediathekView: https://mediathekview.de/</span>
+
+<span class="sd">To demonstrate the power of database engines, here is a more complex example</span>
+<span class="sd">which reads from a MediathekView_ (DE) movie database. For this example of the</span>
+<span class="sd">SQLite engine download the database:</span>
+
+<span class="sd">- https://liste.mediathekview.de/filmliste-v2.db.bz2</span>
+
+<span class="sd">and unpack into ``searx/data/filmliste-v2.db``. To search the database use e.g</span>
+<span class="sd">Query to test: ``!mediathekview concert``</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: mediathekview</span>
+<span class="sd"> engine: sqlite</span>
+<span class="sd"> disabled: False</span>
+<span class="sd"> categories: general</span>
+<span class="sd"> result_template: default.html</span>
+<span class="sd"> database: searx/data/filmliste-v2.db</span>
+<span class="sd"> query_str: &gt;-</span>
+<span class="sd"> SELECT title || &#39; (&#39; || time(duration, &#39;unixepoch&#39;) || &#39;)&#39; AS title,</span>
+<span class="sd"> COALESCE( NULLIF(url_video_hd,&#39;&#39;), NULLIF(url_video_sd,&#39;&#39;), url_video) AS url,</span>
+<span class="sd"> description AS content</span>
+<span class="sd"> FROM film</span>
+<span class="sd"> WHERE title LIKE :wildcard OR description LIKE :wildcard</span>
+<span class="sd"> ORDER BY duration DESC</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">sqlite3</span>
+<span class="kn">import</span> <span class="nn">contextlib</span>
+
+<span class="n">engine_type</span> <span class="o">=</span> <span class="s1">&#39;offline&#39;</span>
+
+<span class="n">database</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;Filename of the SQLite DB.&quot;&quot;&quot;</span>
+
+<span class="n">query_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;SQL query that returns the result items.&quot;&quot;&quot;</span>
+
+<span class="n">limit</span> <span class="o">=</span> <span class="mi">10</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">result_template</span> <span class="o">=</span> <span class="s1">&#39;key-value.html&#39;</span>
+
+
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="p">):</span>
+ <span class="k">if</span> <span class="s1">&#39;query_str&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">engine_settings</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;query_str cannot be empty&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">engine_settings</span><span class="p">[</span><span class="s1">&#39;query_str&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;select &#39;</span><span class="p">):</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;only SELECT query is supported&#39;</span><span class="p">)</span>
+
+
+<div class="viewcode-block" id="sqlite_cursor">
+<a class="viewcode-back" href="../../../dev/engines/offline/sql-engines.html#searx.engines.sqlite.sqlite_cursor">[docs]</a>
+<span class="nd">@contextlib</span><span class="o">.</span><span class="n">contextmanager</span>
+<span class="k">def</span> <span class="nf">sqlite_cursor</span><span class="p">():</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Implements a :py:obj:`Context Manager &lt;contextlib.contextmanager&gt;` for a</span>
+<span class="sd"> :py:obj:`sqlite3.Cursor`.</span>
+
+<span class="sd"> Open database in read only mode: if the database doesn&#39;t exist. The default</span>
+<span class="sd"> mode creates an empty file on the file system. See:</span>
+
+<span class="sd"> * https://docs.python.org/3/library/sqlite3.html#sqlite3.connect</span>
+<span class="sd"> * https://www.sqlite.org/uri.html</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">uri</span> <span class="o">=</span> <span class="s1">&#39;file:&#39;</span> <span class="o">+</span> <span class="n">database</span> <span class="o">+</span> <span class="s1">&#39;?mode=ro&#39;</span>
+ <span class="k">with</span> <span class="n">contextlib</span><span class="o">.</span><span class="n">closing</span><span class="p">(</span><span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">uri</span><span class="p">,</span> <span class="n">uri</span><span class="o">=</span><span class="kc">True</span><span class="p">))</span> <span class="k">as</span> <span class="n">connect</span><span class="p">:</span>
+ <span class="n">connect</span><span class="o">.</span><span class="n">row_factory</span> <span class="o">=</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">Row</span>
+ <span class="k">with</span> <span class="n">contextlib</span><span class="o">.</span><span class="n">closing</span><span class="p">(</span><span class="n">connect</span><span class="o">.</span><span class="n">cursor</span><span class="p">())</span> <span class="k">as</span> <span class="n">cursor</span><span class="p">:</span>
+ <span class="k">yield</span> <span class="n">cursor</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">search</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="n">query_params</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;wildcard&#39;</span><span class="p">:</span> <span class="sa">r</span><span class="s1">&#39;%&#39;</span> <span class="o">+</span> <span class="n">query</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39; &#39;</span><span class="p">,</span> <span class="sa">r</span><span class="s1">&#39;%&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="sa">r</span><span class="s1">&#39;%&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;limit&#39;</span><span class="p">:</span> <span class="n">limit</span><span class="p">,</span>
+ <span class="s1">&#39;offset&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">limit</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="n">query_to_run</span> <span class="o">=</span> <span class="n">query_str</span> <span class="o">+</span> <span class="s1">&#39; LIMIT :limit OFFSET :offset&#39;</span>
+
+ <span class="k">with</span> <span class="n">sqlite_cursor</span><span class="p">()</span> <span class="k">as</span> <span class="n">cur</span><span class="p">:</span>
+
+ <span class="n">cur</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query_to_run</span><span class="p">,</span> <span class="n">query_params</span><span class="p">)</span>
+ <span class="n">col_names</span> <span class="o">=</span> <span class="p">[</span><span class="n">cn</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">for</span> <span class="n">cn</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">]</span>
+
+ <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">():</span>
+ <span class="n">item</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">col_names</span><span class="p">,</span> <span class="nb">map</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">row</span><span class="p">)))</span>
+ <span class="n">item</span><span class="p">[</span><span class="s1">&#39;template&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">result_template</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;append result --&gt; </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">item</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/startpage.html b/_modules/searx/engines/startpage.html
new file mode 100644
index 000000000..5259db4eb
--- /dev/null
+++ b/_modules/searx/engines/startpage.html
@@ -0,0 +1,610 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.startpage &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.startpage</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.startpage</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Startpage&#39;s language &amp; region selectors are a mess ..</span>
+
+<span class="sd">.. _startpage regions:</span>
+
+<span class="sd">Startpage regions</span>
+<span class="sd">=================</span>
+
+<span class="sd">In the list of regions there are tags we need to map to common region tags::</span>
+
+<span class="sd"> pt-BR_BR --&gt; pt_BR</span>
+<span class="sd"> zh-CN_CN --&gt; zh_Hans_CN</span>
+<span class="sd"> zh-TW_TW --&gt; zh_Hant_TW</span>
+<span class="sd"> zh-TW_HK --&gt; zh_Hant_HK</span>
+<span class="sd"> en-GB_GB --&gt; en_GB</span>
+
+<span class="sd">and there is at least one tag with a three letter language tag (ISO 639-2)::</span>
+
+<span class="sd"> fil_PH --&gt; fil_PH</span>
+
+<span class="sd">The locale code ``no_NO`` from Startpage does not exists and is mapped to</span>
+<span class="sd">``nb-NO``::</span>
+
+<span class="sd"> babel.core.UnknownLocaleError: unknown locale &#39;no_NO&#39;</span>
+
+<span class="sd">For reference see languages-subtag at iana; ``no`` is the macrolanguage [1]_ and</span>
+<span class="sd">W3C recommends subtag over macrolanguage [2]_.</span>
+
+<span class="sd">.. [1] `iana: language-subtag-registry</span>
+<span class="sd"> &lt;https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry&gt;`_ ::</span>
+
+<span class="sd"> type: language</span>
+<span class="sd"> Subtag: nb</span>
+<span class="sd"> Description: Norwegian Bokmål</span>
+<span class="sd"> Added: 2005-10-16</span>
+<span class="sd"> Suppress-Script: Latn</span>
+<span class="sd"> Macrolanguage: no</span>
+
+<span class="sd">.. [2]</span>
+<span class="sd"> Use macrolanguages with care. Some language subtags have a Scope field set to</span>
+<span class="sd"> macrolanguage, i.e. this primary language subtag encompasses a number of more</span>
+<span class="sd"> specific primary language subtags in the registry. ... As we recommended for</span>
+<span class="sd"> the collection subtags mentioned above, in most cases you should try to use</span>
+<span class="sd"> the more specific subtags ... `W3: The primary language subtag</span>
+<span class="sd"> &lt;https://www.w3.org/International/questions/qa-choosing-language-tags#langsubtag&gt;`_</span>
+
+<span class="sd">.. _startpage languages:</span>
+
+<span class="sd">Startpage languages</span>
+<span class="sd">===================</span>
+
+<span class="sd">:py:obj:`send_accept_language_header`:</span>
+<span class="sd"> The displayed name in Startpage&#39;s settings page depend on the location of the</span>
+<span class="sd"> IP when ``Accept-Language`` HTTP header is unset. In :py:obj:`fetch_traits`</span>
+<span class="sd"> we use::</span>
+
+<span class="sd"> &#39;Accept-Language&#39;: &quot;en-US,en;q=0.5&quot;,</span>
+<span class="sd"> ..</span>
+
+<span class="sd"> to get uniform names independent from the IP).</span>
+
+<span class="sd">.. _startpage categories:</span>
+
+<span class="sd">Startpage categories</span>
+<span class="sd">====================</span>
+
+<span class="sd">Startpage&#39;s category (for Web-search, News, Videos, ..) is set by</span>
+<span class="sd">:py:obj:`startpage_categ` in settings.yml::</span>
+
+<span class="sd"> - name: startpage</span>
+<span class="sd"> engine: startpage</span>
+<span class="sd"> startpage_categ: web</span>
+<span class="sd"> ...</span>
+
+<span class="sd">.. hint::</span>
+
+<span class="sd"> The default category is ``web`` .. and other categories than ``web`` are not</span>
+<span class="sd"> yet implemented.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="c1"># pylint: disable=too-many-statements</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">collections</span> <span class="kn">import</span> <span class="n">OrderedDict</span>
+<span class="kn">import</span> <span class="nn">re</span>
+<span class="kn">from</span> <span class="nn">unicodedata</span> <span class="kn">import</span> <span class="n">normalize</span><span class="p">,</span> <span class="n">combining</span>
+<span class="kn">from</span> <span class="nn">time</span> <span class="kn">import</span> <span class="n">time</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
+
+<span class="kn">import</span> <span class="nn">dateutil.parser</span>
+<span class="kn">import</span> <span class="nn">lxml.html</span>
+<span class="kn">import</span> <span class="nn">babel.localedata</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">gen_useragent</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineCaptchaException</span>
+<span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">region_tag</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://startpage.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q2333295&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">startpage_categ</span> <span class="o">=</span> <span class="s1">&#39;web&#39;</span>
+<span class="sd">&quot;&quot;&quot;Startpage&#39;s category, visit :ref:`startpage categories`.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="sd">&quot;&quot;&quot;Startpage tries to guess user&#39;s language and territory from the HTTP</span>
+<span class="sd">``Accept-Language``. Optional the user can select a search-language (can be</span>
+<span class="sd">different to the UI language) and a region filter.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">max_page</span> <span class="o">=</span> <span class="mi">18</span>
+<span class="sd">&quot;&quot;&quot;Tested 18 pages maximum (argument ``page``), to be save max is set to 20.&quot;&quot;&quot;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">True</span>
+
+<span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="s1">&#39;d&#39;</span><span class="p">,</span> <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="s1">&#39;w&#39;</span><span class="p">,</span> <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="s1">&#39;m&#39;</span><span class="p">,</span> <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="s1">&#39;y&#39;</span><span class="p">}</span>
+<span class="n">safesearch_dict</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;0&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;1&#39;</span><span class="p">}</span>
+
+<span class="c1"># search-url</span>
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://www.startpage.com&#39;</span>
+<span class="n">search_url</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;/sp/search&#39;</span>
+
+<span class="c1"># specific xpath variables</span>
+<span class="c1"># ads xpath //div[@id=&quot;results&quot;]/div[@id=&quot;sponsored&quot;]//div[@class=&quot;result&quot;]</span>
+<span class="c1"># not ads: div[@class=&quot;result&quot;] are the direct children of div[@id=&quot;results&quot;]</span>
+<span class="n">search_form_xpath</span> <span class="o">=</span> <span class="s1">&#39;//form[@id=&quot;search&quot;]&#39;</span>
+<span class="sd">&quot;&quot;&quot;XPath of Startpage&#39;s origin search form</span>
+
+<span class="sd">.. code: html</span>
+
+<span class="sd"> &lt;form action=&quot;/sp/search&quot; method=&quot;post&quot;&gt;</span>
+<span class="sd"> &lt;input type=&quot;text&quot; name=&quot;query&quot; value=&quot;&quot; ..&gt;</span>
+<span class="sd"> &lt;input type=&quot;hidden&quot; name=&quot;t&quot; value=&quot;device&quot;&gt;</span>
+<span class="sd"> &lt;input type=&quot;hidden&quot; name=&quot;lui&quot; value=&quot;english&quot;&gt;</span>
+<span class="sd"> &lt;input type=&quot;hidden&quot; name=&quot;sc&quot; value=&quot;Q7Mt5TRqowKB00&quot;&gt;</span>
+<span class="sd"> &lt;input type=&quot;hidden&quot; name=&quot;cat&quot; value=&quot;web&quot;&gt;</span>
+<span class="sd"> &lt;input type=&quot;hidden&quot; class=&quot;abp&quot; id=&quot;abp-input&quot; name=&quot;abp&quot; value=&quot;1&quot;&gt;</span>
+<span class="sd"> &lt;/form&gt;</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="c1"># timestamp of the last fetch of &#39;sc&#39; code</span>
+<span class="n">sc_code_ts</span> <span class="o">=</span> <span class="mi">0</span>
+<span class="n">sc_code</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="n">sc_code_cache_sec</span> <span class="o">=</span> <span class="mi">30</span>
+<span class="sd">&quot;&quot;&quot;Time in seconds the sc-code is cached in memory :py:obj:`get_sc_code`.&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="get_sc_code">
+<a class="viewcode-back" href="../../../dev/engines/online/startpage.html#searx.engines.startpage.get_sc_code">[docs]</a>
+<span class="k">def</span> <span class="nf">get_sc_code</span><span class="p">(</span><span class="n">searxng_locale</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get an actual ``sc`` argument from Startpage&#39;s search form (HTML page).</span>
+
+<span class="sd"> Startpage puts a ``sc`` argument on every HTML :py:obj:`search form</span>
+<span class="sd"> &lt;search_form_xpath&gt;`. Without this argument Startpage considers the request</span>
+<span class="sd"> is from a bot. We do not know what is encoded in the value of the ``sc``</span>
+<span class="sd"> argument, but it seems to be a kind of a *time-stamp*.</span>
+
+<span class="sd"> Startpage&#39;s search form generates a new sc-code on each request. This</span>
+<span class="sd"> function scrap a new sc-code from Startpage&#39;s home page every</span>
+<span class="sd"> :py:obj:`sc_code_cache_sec` seconds.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="k">global</span> <span class="n">sc_code_ts</span><span class="p">,</span> <span class="n">sc_code</span> <span class="c1"># pylint: disable=global-statement</span>
+
+ <span class="k">if</span> <span class="n">sc_code</span> <span class="ow">and</span> <span class="p">(</span><span class="n">time</span><span class="p">()</span> <span class="o">&lt;</span> <span class="p">(</span><span class="n">sc_code_ts</span> <span class="o">+</span> <span class="n">sc_code_cache_sec</span><span class="p">)):</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;get_sc_code: reuse &#39;</span><span class="si">%s</span><span class="s2">&#39;&quot;</span><span class="p">,</span> <span class="n">sc_code</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">sc_code</span>
+
+ <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="o">**</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]}</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Origin&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Referer&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;/&#39;</span>
+ <span class="c1"># headers[&#39;Connection&#39;] = &#39;keep-alive&#39;</span>
+ <span class="c1"># headers[&#39;Accept-Encoding&#39;] = &#39;gzip, deflate, br&#39;</span>
+ <span class="c1"># headers[&#39;Accept&#39;] = &#39;text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8&#39;</span>
+ <span class="c1"># headers[&#39;User-Agent&#39;] = &#39;Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0&#39;</span>
+
+ <span class="c1"># add Accept-Language header</span>
+ <span class="k">if</span> <span class="n">searxng_locale</span> <span class="o">==</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
+ <span class="n">searxng_locale</span> <span class="o">=</span> <span class="s1">&#39;en-US&#39;</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">searxng_locale</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">send_accept_language_header</span><span class="p">:</span>
+ <span class="n">ac_lang</span> <span class="o">=</span> <span class="n">locale</span><span class="o">.</span><span class="n">language</span>
+ <span class="k">if</span> <span class="n">locale</span><span class="o">.</span><span class="n">territory</span><span class="p">:</span>
+ <span class="n">ac_lang</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">-</span><span class="si">%s</span><span class="s2">,</span><span class="si">%s</span><span class="s2">;q=0.9,*;q=0.5&quot;</span> <span class="o">%</span> <span class="p">(</span>
+ <span class="n">locale</span><span class="o">.</span><span class="n">language</span><span class="p">,</span>
+ <span class="n">locale</span><span class="o">.</span><span class="n">territory</span><span class="p">,</span>
+ <span class="n">locale</span><span class="o">.</span><span class="n">language</span><span class="p">,</span>
+ <span class="p">)</span>
+ <span class="n">headers</span><span class="p">[</span><span class="s1">&#39;Accept-Language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">ac_lang</span>
+
+ <span class="n">get_sc_url</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;/?sc=</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sc_code</span><span class="p">)</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;query new sc time-stamp ... </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">get_sc_url</span><span class="p">)</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;headers: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">headers</span><span class="p">)</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">get_sc_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+
+ <span class="c1"># ?? x = network.get(&#39;https://www.startpage.com/sp/cdn/images/filter-chevron.svg&#39;, headers=headers)</span>
+ <span class="c1"># ?? https://www.startpage.com/sp/cdn/images/filter-chevron.svg</span>
+ <span class="c1"># ?? ping-back URL: https://www.startpage.com/sp/pb?sc=TLsB0oITjZ8F21</span>
+
+ <span class="k">if</span> <span class="nb">str</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">url</span><span class="p">)</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;https://www.startpage.com/sp/captcha&#39;</span><span class="p">):</span> <span class="c1"># type: ignore</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">(</span>
+ <span class="n">message</span><span class="o">=</span><span class="s2">&quot;get_sc_code: got redirected to https://www.startpage.com/sp/captcha&quot;</span><span class="p">,</span>
+ <span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sc_code</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">search_form_xpath</span> <span class="o">+</span> <span class="s1">&#39;//input[@name=&quot;sc&quot;]/@value&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="k">except</span> <span class="ne">IndexError</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;suspend startpage API --&gt; https://github.com/searxng/searxng/pull/695&quot;</span><span class="p">)</span>
+ <span class="k">raise</span> <span class="n">SearxEngineCaptchaException</span><span class="p">(</span>
+ <span class="n">message</span><span class="o">=</span><span class="s2">&quot;get_sc_code: [PR-695] query new sc time-stamp failed! (</span><span class="si">%s</span><span class="s2">)&quot;</span> <span class="o">%</span> <span class="n">resp</span><span class="o">.</span><span class="n">url</span><span class="p">,</span> <span class="c1"># type: ignore</span>
+ <span class="p">)</span> <span class="kn">from</span> <span class="nn">exc</span>
+
+ <span class="n">sc_code_ts</span> <span class="o">=</span> <span class="n">time</span><span class="p">()</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;get_sc_code: new value is: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">sc_code</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">sc_code</span></div>
+
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/startpage.html#searx.engines.startpage.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a Startpage request.</span>
+
+<span class="sd"> To avoid CAPTCHA we need to send a well formed HTTP POST request with a</span>
+<span class="sd"> cookie. We need to form a request that is identical to the request build by</span>
+<span class="sd"> Startpage&#39;s search form:</span>
+
+<span class="sd"> - in the cookie the **region** is selected</span>
+<span class="sd"> - in the HTTP POST data the **language** is selected</span>
+
+<span class="sd"> Additionally the arguments form Startpage&#39;s search form needs to be set in</span>
+<span class="sd"> HTML POST data / compare ``&lt;input&gt;`` elements: :py:obj:`search_form_xpath`.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="n">startpage_categ</span> <span class="o">==</span> <span class="s1">&#39;web&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">_request_cat_web</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Startpages&#39;s category &#39;%&#39; is not yet implemented.&quot;</span><span class="p">,</span> <span class="n">startpage_categ</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">_request_cat_web</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="n">engine_region</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en-US&#39;</span><span class="p">)</span>
+ <span class="n">engine_language</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="s1">&#39;en&#39;</span><span class="p">)</span>
+
+ <span class="c1"># build arguments</span>
+ <span class="n">args</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;cat&#39;</span><span class="p">:</span> <span class="s1">&#39;web&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;t&#39;</span><span class="p">:</span> <span class="s1">&#39;device&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sc&#39;</span><span class="p">:</span> <span class="n">get_sc_code</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">params</span><span class="p">),</span> <span class="c1"># hint: this func needs HTTP headers,</span>
+ <span class="s1">&#39;with_date&#39;</span><span class="p">:</span> <span class="n">time_range_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">],</span> <span class="s1">&#39;&#39;</span><span class="p">),</span>
+ <span class="p">}</span>
+
+ <span class="k">if</span> <span class="n">engine_language</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_language</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;lui&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_language</span>
+
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;abp&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">args</span><span class="p">[</span><span class="s1">&#39;page&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span>
+
+ <span class="c1"># build cookie</span>
+ <span class="n">lang_homepage</span> <span class="o">=</span> <span class="s1">&#39;en&#39;</span>
+ <span class="n">cookie</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">()</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;date_time&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;world&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;disable_family_filter&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">safesearch_dict</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]]</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;disable_open_in_new_window&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;0&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;enable_post_method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span> <span class="c1"># hint: POST</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;enable_proxy_safety_suggest&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;enable_stay_control&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;instant_answers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;lang_homepage&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;s/device/</span><span class="si">%s</span><span class="s1">/&#39;</span> <span class="o">%</span> <span class="n">lang_homepage</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;num_of_results&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;10&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;suggestions&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;1&#39;</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;wt_unit&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;celsius&#39;</span>
+
+ <span class="k">if</span> <span class="n">engine_language</span><span class="p">:</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_language</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;language_ui&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_language</span>
+
+ <span class="k">if</span> <span class="n">engine_region</span><span class="p">:</span>
+ <span class="n">cookie</span><span class="p">[</span><span class="s1">&#39;search_results_region&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">engine_region</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;preferences&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;N1N&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="s2">&quot;</span><span class="si">%s</span><span class="s2">EEE</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">cookie</span><span class="o">.</span><span class="n">items</span><span class="p">()])</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;cookie preferences: </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">][</span><span class="s1">&#39;preferences&#39;</span><span class="p">])</span>
+
+ <span class="c1"># POST request</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;data: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">args</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;POST&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Origin&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">][</span><span class="s1">&#39;Referer&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;/&#39;</span>
+ <span class="c1"># is the Accept header needed?</span>
+ <span class="c1"># params[&#39;headers&#39;][&#39;Accept&#39;] = &#39;text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8&#39;</span>
+
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="c1"># get response from search-request</span>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">startpage_categ</span> <span class="o">==</span> <span class="s1">&#39;web&#39;</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">_response_cat_web</span><span class="p">(</span><span class="n">dom</span><span class="p">)</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s2">&quot;Startpages&#39;s category &#39;%&#39; is not yet implemented.&quot;</span><span class="p">,</span> <span class="n">startpage_categ</span><span class="p">)</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+
+<span class="k">def</span> <span class="nf">_response_cat_web</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># parse results</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[@class=&quot;w-gl&quot;]/div[contains(@class, &quot;result&quot;)]&#39;</span><span class="p">):</span>
+ <span class="n">links</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//a[contains(@class, &quot;result-title result-link&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">links</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">link</span> <span class="o">=</span> <span class="n">links</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">link</span><span class="o">.</span><span class="n">attrib</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;href&#39;</span><span class="p">)</span>
+
+ <span class="c1"># block google-ad url&#39;s</span>
+ <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;^http(s|)://(www\.)?google\.[a-z]+/aclk.*$&quot;</span><span class="p">,</span> <span class="n">url</span><span class="p">):</span>
+ <span class="k">continue</span>
+
+ <span class="c1"># block startpage search url&#39;s</span>
+ <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;^http(s|)://(www\.)?startpage\.com/do/search\?.*$&quot;</span><span class="p">,</span> <span class="n">url</span><span class="p">):</span>
+ <span class="k">continue</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="s1">&#39;h2&#39;</span><span class="p">))</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//p[contains(@class, &quot;description&quot;)]&#39;</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">allow_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="ow">or</span> <span class="s1">&#39;&#39;</span>
+
+ <span class="n">published_date</span> <span class="o">=</span> <span class="kc">None</span>
+
+ <span class="c1"># check if search result starts with something like: &quot;2 Sep 2014 ... &quot;</span>
+ <span class="k">if</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;^([1-9]|[1-2][0-9]|3[0-1]) [A-Z][a-z]</span><span class="si">{2}</span><span class="s2"> [0-9]</span><span class="si">{4}</span><span class="s2"> \.\.\. &quot;</span><span class="p">,</span> <span class="n">content</span><span class="p">):</span>
+ <span class="n">date_pos</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;...&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">4</span>
+ <span class="n">date_string</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="n">date_pos</span> <span class="o">-</span> <span class="mi">5</span><span class="p">]</span>
+ <span class="c1"># fix content string</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="n">date_pos</span><span class="p">:]</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">published_date</span> <span class="o">=</span> <span class="n">dateutil</span><span class="o">.</span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">date_string</span><span class="p">,</span> <span class="n">dayfirst</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
+ <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
+ <span class="k">pass</span>
+
+ <span class="c1"># check if search result starts with something like: &quot;5 days ago ... &quot;</span>
+ <span class="k">elif</span> <span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;^[0-9]+ days? ago \.\.\. &quot;</span><span class="p">,</span> <span class="n">content</span><span class="p">):</span>
+ <span class="n">date_pos</span> <span class="o">=</span> <span class="n">content</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;...&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">4</span>
+ <span class="n">date_string</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="mi">0</span> <span class="p">:</span> <span class="n">date_pos</span> <span class="o">-</span> <span class="mi">5</span><span class="p">]</span>
+
+ <span class="c1"># calculate datetime</span>
+ <span class="n">published_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">-</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">days</span><span class="o">=</span><span class="nb">int</span><span class="p">(</span><span class="n">re</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;\d+&#39;</span><span class="p">,</span> <span class="n">date_string</span><span class="p">)</span><span class="o">.</span><span class="n">group</span><span class="p">()))</span> <span class="c1"># type: ignore</span>
+
+ <span class="c1"># fix content string</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">content</span><span class="p">[</span><span class="n">date_pos</span><span class="p">:]</span>
+
+ <span class="k">if</span> <span class="n">published_date</span><span class="p">:</span>
+ <span class="c1"># append result</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span> <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">published_date</span><span class="p">})</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="c1"># append result</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">})</span>
+
+ <span class="c1"># return results</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/startpage.html#searx.engines.startpage.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch :ref:`languages &lt;startpage languages&gt;` and :ref:`regions &lt;startpage</span>
+<span class="sd"> regions&gt;` from Startpage.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=too-many-branches</span>
+
+ <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;User-Agent&#39;</span><span class="p">:</span> <span class="n">gen_useragent</span><span class="p">(),</span>
+ <span class="s1">&#39;Accept-Language&#39;</span><span class="p">:</span> <span class="s2">&quot;en-US,en;q=0.5&quot;</span><span class="p">,</span> <span class="c1"># bing needs to set the English language</span>
+ <span class="p">}</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://www.startpage.com/do/settings&#39;</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from Startpage is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">lxml</span><span class="o">.</span><span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="c1"># regions</span>
+
+ <span class="n">sp_region_names</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">for</span> <span class="n">option</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//form[@name=&quot;settings&quot;]//select[@name=&quot;search_results_region&quot;]/option&#39;</span><span class="p">):</span>
+ <span class="n">sp_region_names</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">option</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="n">eng_tag</span> <span class="ow">in</span> <span class="n">sp_region_names</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="o">==</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">babel_region_tag</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;no_NO&#39;</span><span class="p">:</span> <span class="s1">&#39;nb_NO&#39;</span><span class="p">}</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">)</span> <span class="c1"># norway</span>
+
+ <span class="k">if</span> <span class="s1">&#39;-&#39;</span> <span class="ow">in</span> <span class="n">babel_region_tag</span><span class="p">:</span>
+ <span class="n">l</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">babel_region_tag</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="n">r</span> <span class="o">=</span> <span class="n">r</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="s1">&#39;_&#39;</span> <span class="o">+</span> <span class="n">r</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;_&#39;</span><span class="p">))</span>
+
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">region_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">babel_region_tag</span><span class="p">,</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;_&#39;</span><span class="p">))</span>
+
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: can&#39;t determine babel locale of startpage&#39;s locale </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="c1"># languages</span>
+
+ <span class="n">catalog_engine2code</span> <span class="o">=</span> <span class="p">{</span><span class="n">name</span><span class="o">.</span><span class="n">lower</span><span class="p">():</span> <span class="n">lang_code</span> <span class="k">for</span> <span class="n">lang_code</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
+
+ <span class="c1"># get the native name of every language known by babel</span>
+
+ <span class="k">for</span> <span class="n">lang_code</span> <span class="ow">in</span> <span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">lang_code</span><span class="p">:</span> <span class="n">lang_code</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;_&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">babel</span><span class="o">.</span><span class="n">localedata</span><span class="o">.</span><span class="n">locale_identifiers</span><span class="p">()):</span>
+ <span class="n">native_name</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="p">(</span><span class="n">lang_code</span><span class="p">)</span><span class="o">.</span><span class="n">get_language_name</span><span class="p">()</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">native_name</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ERROR: language name of startpage&#39;s language </span><span class="si">{</span><span class="n">lang_code</span><span class="si">}</span><span class="s2"> is unknown by babel&quot;</span><span class="p">)</span>
+ <span class="k">continue</span>
+ <span class="n">native_name</span> <span class="o">=</span> <span class="n">native_name</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span>
+ <span class="c1"># add native name exactly as it is</span>
+ <span class="n">catalog_engine2code</span><span class="p">[</span><span class="n">native_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">lang_code</span>
+
+ <span class="c1"># add &quot;normalized&quot; language name (i.e. français becomes francais and español becomes espanol)</span>
+ <span class="n">unaccented_name</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">c</span><span class="p">:</span> <span class="ow">not</span> <span class="n">combining</span><span class="p">(</span><span class="n">c</span><span class="p">),</span> <span class="n">normalize</span><span class="p">(</span><span class="s1">&#39;NFKD&#39;</span><span class="p">,</span> <span class="n">native_name</span><span class="p">)))</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">unaccented_name</span><span class="p">)</span> <span class="o">==</span> <span class="nb">len</span><span class="p">(</span><span class="n">unaccented_name</span><span class="o">.</span><span class="n">encode</span><span class="p">()):</span>
+ <span class="c1"># add only if result is ascii (otherwise &quot;normalization&quot; didn&#39;t work)</span>
+ <span class="n">catalog_engine2code</span><span class="p">[</span><span class="n">unaccented_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">lang_code</span>
+
+ <span class="c1"># values that can&#39;t be determined by babel&#39;s languages names</span>
+
+ <span class="n">catalog_engine2code</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="c1"># traditional chinese used in ..</span>
+ <span class="s1">&#39;fantizhengwen&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hant&#39;</span><span class="p">,</span>
+ <span class="c1"># Korean alphabet</span>
+ <span class="s1">&#39;hangul&#39;</span><span class="p">:</span> <span class="s1">&#39;ko&#39;</span><span class="p">,</span>
+ <span class="c1"># Malayalam is one of 22 scheduled languages of India.</span>
+ <span class="s1">&#39;malayam&#39;</span><span class="p">:</span> <span class="s1">&#39;ml&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;norsk&#39;</span><span class="p">:</span> <span class="s1">&#39;nb&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sinhalese&#39;</span><span class="p">:</span> <span class="s1">&#39;si&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="n">skip_eng_tags</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;english_uk&#39;</span><span class="p">,</span> <span class="c1"># SearXNG lang &#39;en&#39; already maps to &#39;english&#39;</span>
+ <span class="p">}</span>
+
+ <span class="k">for</span> <span class="n">option</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//form[@name=&quot;settings&quot;]//select[@name=&quot;language&quot;]/option&#39;</span><span class="p">):</span>
+
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">option</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;value&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">eng_tag</span> <span class="ow">in</span> <span class="n">skip_eng_tags</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">option</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="c1"># type: ignore</span>
+
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">catalog_engine2code</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">sxng_tag</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">catalog_engine2code</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/tineye.html b/_modules/searx/engines/tineye.html
new file mode 100644
index 000000000..651f68055
--- /dev/null
+++ b/_modules/searx/engines/tineye.html
@@ -0,0 +1,340 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.tineye &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.tineye</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.tineye</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This engine implements *Tineye - reverse image search*</span>
+
+<span class="sd">Using TinEye, you can search by image or perform what we call a reverse image</span>
+<span class="sd">search. You can do that by uploading an image or searching by URL. You can also</span>
+<span class="sd">simply drag and drop your images to start your search. TinEye constantly crawls</span>
+<span class="sd">the web and adds images to its index. Today, the TinEye index is over 50.2</span>
+<span class="sd">billion images `[tineye.com] &lt;https://tineye.com/how&gt;`_.</span>
+
+<span class="sd">.. hint::</span>
+
+<span class="sd"> This SearXNG engine only supports *&#39;searching by URL&#39;* and it does not use</span>
+<span class="sd"> the official API `[api.tineye.com] &lt;https://api.tineye.com/python/docs/&gt;`_.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+<span class="kn">from</span> <span class="nn">flask_babel</span> <span class="kn">import</span> <span class="n">gettext</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">()</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://tineye.com&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q2382535&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://api.tineye.com/python/docs/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">engine_type</span> <span class="o">=</span> <span class="s1">&#39;online_url_search&#39;</span>
+<span class="sd">&quot;&quot;&quot;:py:obj:`searx.search.processors.online_url_search`&quot;&quot;&quot;</span>
+
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">safesearch</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="n">base_url</span> <span class="o">=</span> <span class="s1">&#39;https://tineye.com&#39;</span>
+<span class="n">search_string</span> <span class="o">=</span> <span class="s1">&#39;/api/v1/result_json/?page=</span><span class="si">{page}</span><span class="s1">&amp;</span><span class="si">{query}</span><span class="s1">&#39;</span>
+
+<span class="n">FORMAT_NOT_SUPPORTED</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span>
+ <span class="s2">&quot;Could not read that image url. This may be due to an unsupported file&quot;</span>
+ <span class="s2">&quot; format. TinEye only supports images that are JPEG, PNG, GIF, BMP, TIFF or WebP.&quot;</span>
+<span class="p">)</span>
+<span class="sd">&quot;&quot;&quot;TinEye error message&quot;&quot;&quot;</span>
+
+<span class="n">NO_SIGNATURE_ERROR</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span>
+ <span class="s2">&quot;The image is too simple to find matches. TinEye requires a basic level of&quot;</span>
+ <span class="s2">&quot; visual detail to successfully identify matches.&quot;</span>
+<span class="p">)</span>
+<span class="sd">&quot;&quot;&quot;TinEye error message&quot;&quot;&quot;</span>
+
+<span class="n">DOWNLOAD_ERROR</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;The image could not be downloaded.&quot;</span><span class="p">)</span>
+<span class="sd">&quot;&quot;&quot;TinEye error message&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online_url_search/tineye.html#searx.engines.tineye.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Build TinEye HTTP request using ``search_urls`` of a :py:obj:`engine_type`.&quot;&quot;&quot;</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;raise_for_httperror&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;search_urls&#39;</span><span class="p">][</span><span class="s1">&#39;data:image&#39;</span><span class="p">]:</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;search_urls&#39;</span><span class="p">][</span><span class="s1">&#39;data:image&#39;</span><span class="p">]</span>
+ <span class="k">elif</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;search_urls&#39;</span><span class="p">][</span><span class="s1">&#39;http&#39;</span><span class="p">]:</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;search_urls&#39;</span><span class="p">][</span><span class="s1">&#39;http&#39;</span><span class="p">]</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;query URL: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">})</span>
+
+ <span class="c1"># see https://github.com/TinEye/pytineye/blob/main/pytineye/api.py</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="n">search_string</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="n">query</span><span class="p">,</span> <span class="n">page</span><span class="o">=</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">])</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;Connection&#39;</span><span class="p">:</span> <span class="s1">&#39;keep-alive&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;Accept-Encoding&#39;</span><span class="p">:</span> <span class="s1">&#39;gzip, defalte, br&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;Host&#39;</span><span class="p">:</span> <span class="s1">&#39;tineye.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;DNT&#39;</span><span class="p">:</span> <span class="s1">&#39;1&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;TE&#39;</span><span class="p">:</span> <span class="s1">&#39;trailers&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="parse_tineye_match">
+<a class="viewcode-back" href="../../../dev/engines/online_url_search/tineye.html#searx.engines.tineye.parse_tineye_match">[docs]</a>
+<span class="k">def</span> <span class="nf">parse_tineye_match</span><span class="p">(</span><span class="n">match_json</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Takes parsed JSON from the API server and turns it into a :py:obj:`dict`</span>
+<span class="sd"> object.</span>
+
+<span class="sd"> Attributes `(class Match) &lt;https://github.com/TinEye/pytineye/blob/main/pytineye/api.py&gt;`__</span>
+
+<span class="sd"> - `image_url`, link to the result image.</span>
+<span class="sd"> - `domain`, domain this result was found on.</span>
+<span class="sd"> - `score`, a number (0 to 100) that indicates how closely the images match.</span>
+<span class="sd"> - `width`, image width in pixels.</span>
+<span class="sd"> - `height`, image height in pixels.</span>
+<span class="sd"> - `size`, image area in pixels.</span>
+<span class="sd"> - `format`, image format.</span>
+<span class="sd"> - `filesize`, image size in bytes.</span>
+<span class="sd"> - `overlay`, overlay URL.</span>
+<span class="sd"> - `tags`, whether this match belongs to a collection or stock domain.</span>
+
+<span class="sd"> - `backlinks`, a list of Backlink objects pointing to the original websites</span>
+<span class="sd"> and image URLs. List items are instances of :py:obj:`dict`, (`Backlink</span>
+<span class="sd"> &lt;https://github.com/TinEye/pytineye/blob/main/pytineye/api.py&gt;`__):</span>
+
+<span class="sd"> - `url`, the image URL to the image.</span>
+<span class="sd"> - `backlink`, the original website URL.</span>
+<span class="sd"> - `crawl_date`, the date the image was crawled.</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="c1"># HINT: there exists an alternative backlink dict in the domains list / e.g.::</span>
+ <span class="c1">#</span>
+ <span class="c1"># match_json[&#39;domains&#39;][0][&#39;backlinks&#39;]</span>
+
+ <span class="n">backlinks</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">if</span> <span class="s2">&quot;backlinks&quot;</span> <span class="ow">in</span> <span class="n">match_json</span><span class="p">:</span>
+
+ <span class="k">for</span> <span class="n">backlink_json</span> <span class="ow">in</span> <span class="n">match_json</span><span class="p">[</span><span class="s2">&quot;backlinks&quot;</span><span class="p">]:</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">backlink_json</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
+ <span class="k">continue</span>
+
+ <span class="n">crawl_date</span> <span class="o">=</span> <span class="n">backlink_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;crawl_date&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">crawl_date</span><span class="p">:</span>
+ <span class="n">crawl_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">crawl_date</span><span class="p">,</span> <span class="s1">&#39;%Y-%m-</span><span class="si">%d</span><span class="s1">&#39;</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">crawl_date</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">min</span>
+
+ <span class="n">backlinks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">backlink_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;url&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;backlink&#39;</span><span class="p">:</span> <span class="n">backlink_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;backlink&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;crawl_date&#39;</span><span class="p">:</span> <span class="n">crawl_date</span><span class="p">,</span>
+ <span class="s1">&#39;image_name&#39;</span><span class="p">:</span> <span class="n">backlink_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;image_name&quot;</span><span class="p">),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="p">{</span>
+ <span class="s1">&#39;image_url&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;image_url&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;domain&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;domain&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;score&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;score&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;width&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;width&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;height&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;height&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;size&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;size&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;image_format&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;format&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;filesize&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;filesize&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;overlay&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;overlay&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;tags&#39;</span><span class="p">:</span> <span class="n">match_json</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;tags&quot;</span><span class="p">),</span>
+ <span class="s1">&#39;backlinks&#39;</span><span class="p">:</span> <span class="n">backlinks</span><span class="p">,</span>
+ <span class="p">}</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online_url_search/tineye.html#searx.engines.tineye.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse HTTP response from TinEye.&quot;&quot;&quot;</span>
+
+ <span class="c1"># handle the 422 client side errors, and the possible 400 status code error</span>
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="ow">in</span> <span class="p">(</span><span class="mi">400</span><span class="p">,</span> <span class="mi">422</span><span class="p">):</span>
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+ <span class="n">suggestions</span> <span class="o">=</span> <span class="n">json_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;suggestions&#39;</span><span class="p">,</span> <span class="p">{})</span>
+ <span class="n">message</span> <span class="o">=</span> <span class="sa">f</span><span class="s1">&#39;HTTP Status Code: </span><span class="si">{</span><span class="n">resp</span><span class="o">.</span><span class="n">status_code</span><span class="si">}</span><span class="s1">&#39;</span>
+
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">422</span><span class="p">:</span>
+ <span class="n">s_key</span> <span class="o">=</span> <span class="n">suggestions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;key&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">s_key</span> <span class="o">==</span> <span class="s2">&quot;Invalid image URL&quot;</span><span class="p">:</span>
+ <span class="c1"># test https://docs.searxng.org/_static/searxng-wordmark.svg</span>
+ <span class="n">message</span> <span class="o">=</span> <span class="n">FORMAT_NOT_SUPPORTED</span>
+ <span class="k">elif</span> <span class="n">s_key</span> <span class="o">==</span> <span class="s1">&#39;NO_SIGNATURE_ERROR&#39;</span><span class="p">:</span>
+ <span class="c1"># test https://pngimg.com/uploads/dot/dot_PNG4.png</span>
+ <span class="n">message</span> <span class="o">=</span> <span class="n">NO_SIGNATURE_ERROR</span>
+ <span class="k">elif</span> <span class="n">s_key</span> <span class="o">==</span> <span class="s1">&#39;Download Error&#39;</span><span class="p">:</span>
+ <span class="c1"># test https://notexists</span>
+ <span class="n">message</span> <span class="o">=</span> <span class="n">DOWNLOAD_ERROR</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s2">&quot;Unknown suggestion key encountered: </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">s_key</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span> <span class="c1"># 400</span>
+ <span class="n">description</span> <span class="o">=</span> <span class="n">suggestions</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">description</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
+ <span class="n">message</span> <span class="o">=</span> <span class="s1">&#39;,&#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">description</span><span class="p">)</span>
+
+ <span class="c1"># see https://github.com/searxng/searxng/pull/1456#issuecomment-1193105023</span>
+ <span class="c1"># results.append({&#39;answer&#39;: message})</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="c1"># Raise for all other responses</span>
+ <span class="n">resp</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">json_data</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+
+ <span class="k">for</span> <span class="n">match_json</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="s1">&#39;matches&#39;</span><span class="p">]:</span>
+
+ <span class="n">tineye_match</span> <span class="o">=</span> <span class="n">parse_tineye_match</span><span class="p">(</span><span class="n">match_json</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;backlinks&#39;</span><span class="p">]:</span>
+ <span class="k">continue</span>
+
+ <span class="n">backlink</span> <span class="o">=</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;backlinks&#39;</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;images.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">backlink</span><span class="p">[</span><span class="s1">&#39;backlink&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;thumbnail_src&#39;</span><span class="p">:</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;image_url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;source&#39;</span><span class="p">:</span> <span class="n">backlink</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">backlink</span><span class="p">[</span><span class="s1">&#39;image_name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">backlink</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;format&#39;</span><span class="p">:</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;image_format&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;width&#39;</span><span class="p">:</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;width&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;height&#39;</span><span class="p">:</span> <span class="n">tineye_match</span><span class="p">[</span><span class="s1">&#39;height&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">backlink</span><span class="p">[</span><span class="s1">&#39;crawl_date&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="c1"># append number of results</span>
+
+ <span class="n">number_of_results</span> <span class="o">=</span> <span class="n">json_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;num_matches&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">number_of_results</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;number_of_results&#39;</span><span class="p">:</span> <span class="n">number_of_results</span><span class="p">})</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/torznab.html b/_modules/searx/engines/torznab.html
new file mode 100644
index 000000000..2109ad94f
--- /dev/null
+++ b/_modules/searx/engines/torznab.html
@@ -0,0 +1,367 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.torznab &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.torznab</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.torznab</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Torznab_ is an API specification that provides a standardized way to query</span>
+<span class="sd">torrent site for content. It is used by a number of torrent applications,</span>
+<span class="sd">including Prowlarr_ and Jackett_.</span>
+
+<span class="sd">Using this engine together with Prowlarr_ or Jackett_ allows you to search</span>
+<span class="sd">a huge number of torrent sites which are not directly supported.</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The engine has the following settings:</span>
+
+<span class="sd">``base_url``:</span>
+<span class="sd"> Torznab endpoint URL.</span>
+
+<span class="sd">``api_key``:</span>
+<span class="sd"> The API key to use for authentication.</span>
+
+<span class="sd">``torznab_categories``:</span>
+<span class="sd"> The categories to use for searching. This is a list of category IDs. See</span>
+<span class="sd"> Prowlarr-categories_ or Jackett-categories_ for more information.</span>
+
+<span class="sd">``show_torrent_files``:</span>
+<span class="sd"> Whether to show the torrent file in the search results. Be careful as using</span>
+<span class="sd"> this with Prowlarr_ or Jackett_ leaks the API key. This should be used only</span>
+<span class="sd"> if you are querying a Torznab endpoint without authentication or if the</span>
+<span class="sd"> instance is private. Be aware that private trackers may ban you if you share</span>
+<span class="sd"> the torrent file. Defaults to ``false``.</span>
+
+<span class="sd">``show_magnet_links``:</span>
+<span class="sd"> Whether to show the magnet link in the search results. Be aware that private</span>
+<span class="sd"> trackers may ban you if you share the magnet link. Defaults to ``true``.</span>
+
+<span class="sd">.. _Torznab:</span>
+<span class="sd"> https://torznab.github.io/spec-1.3-draft/index.html</span>
+<span class="sd">.. _Prowlarr:</span>
+<span class="sd"> https://github.com/Prowlarr/Prowlarr</span>
+<span class="sd">.. _Jackett:</span>
+<span class="sd"> https://github.com/Jackett/Jackett</span>
+<span class="sd">.. _Prowlarr-categories:</span>
+<span class="sd"> https://wiki.servarr.com/en/prowlarr/cardigann-yml-definition#categories</span>
+<span class="sd">.. _Jackett-categories:</span>
+<span class="sd"> https://github.com/Jackett/Jackett/wiki/Jackett-Categories</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">etree</span> <span class="c1"># type: ignore</span>
+
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxEngineAPIException</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">humanize_bytes</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">httpx</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="c1"># engine settings</span>
+<span class="n">about</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s2">&quot;https://torznab.github.io/spec-1.3-draft&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;XML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="n">categories</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;files&#39;</span><span class="p">]</span>
+<span class="n">paging</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="n">time_range_support</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+
+<span class="c1"># defined in settings.yml</span>
+<span class="c1"># example (Jackett): &quot;http://localhost:9117/api/v2.0/indexers/all/results/torznab&quot;</span>
+<span class="n">base_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="n">api_key</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="c1"># https://newznab.readthedocs.io/en/latest/misc/api/#predefined-categories</span>
+<span class="n">torznab_categories</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="n">show_torrent_files</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="n">show_magnet_links</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Initialize the engine.&quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">base_url</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s1">&#39;missing torznab base_url&#39;</span><span class="p">)</span></div>
+
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">params</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Build the request params.&quot;&quot;&quot;</span>
+ <span class="n">search_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">base_url</span> <span class="o">+</span> <span class="s1">&#39;?t=search&amp;q=</span><span class="si">{search_query}</span><span class="s1">&#39;</span>
+
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">api_key</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">search_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;apikey=</span><span class="si">{api_key}</span><span class="s1">&#39;</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">torznab_categories</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">search_url</span> <span class="o">+=</span> <span class="s1">&#39;&amp;cat=</span><span class="si">{torznab_categories}</span><span class="s1">&#39;</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
+ <span class="n">search_query</span><span class="o">=</span><span class="n">quote</span><span class="p">(</span><span class="n">query</span><span class="p">),</span> <span class="n">api_key</span><span class="o">=</span><span class="n">api_key</span><span class="p">,</span> <span class="n">torznab_categories</span><span class="o">=</span><span class="s2">&quot;,&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">torznab_categories</span><span class="p">])</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">:</span> <span class="n">httpx</span><span class="o">.</span><span class="n">Response</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Parse the XML response and return a list of results.&quot;&quot;&quot;</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">search_results</span> <span class="o">=</span> <span class="n">etree</span><span class="o">.</span><span class="n">XML</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
+
+ <span class="c1"># handle errors: https://newznab.readthedocs.io/en/latest/misc/api/#newznab-error-codes</span>
+ <span class="k">if</span> <span class="n">search_results</span><span class="o">.</span><span class="n">tag</span> <span class="o">==</span> <span class="s2">&quot;error&quot;</span><span class="p">:</span>
+ <span class="k">raise</span> <span class="n">SearxEngineAPIException</span><span class="p">(</span><span class="n">search_results</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;description&quot;</span><span class="p">))</span>
+
+ <span class="n">channel</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span> <span class="o">=</span> <span class="n">search_results</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+
+ <span class="n">item</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span>
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">channel</span><span class="o">.</span><span class="n">iterfind</span><span class="p">(</span><span class="s1">&#39;item&#39;</span><span class="p">):</span>
+ <span class="n">result</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="n">build_result</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<div class="viewcode-block" id="build_result">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.build_result">[docs]</a>
+<span class="k">def</span> <span class="nf">build_result</span><span class="p">(</span><span class="n">item</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Build a result from a XML item.&quot;&quot;&quot;</span>
+
+ <span class="c1"># extract attributes from XML</span>
+ <span class="c1"># see https://torznab.github.io/spec-1.3-draft/torznab/Specification-v1.3.html#predefined-attributes</span>
+ <span class="n">enclosure</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;enclosure&#39;</span><span class="p">)</span>
+ <span class="n">enclosure_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="k">if</span> <span class="n">enclosure</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">enclosure_url</span> <span class="o">=</span> <span class="n">enclosure</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;url&#39;</span><span class="p">)</span>
+
+ <span class="n">filesize</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;size&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">filesize</span> <span class="ow">and</span> <span class="n">enclosure</span><span class="p">:</span>
+ <span class="n">filesize</span> <span class="o">=</span> <span class="n">enclosure</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;length&#39;</span><span class="p">)</span>
+
+ <span class="n">guid</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;guid&#39;</span><span class="p">)</span>
+ <span class="n">comments</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;comments&#39;</span><span class="p">)</span>
+ <span class="n">pubDate</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;pubDate&#39;</span><span class="p">)</span>
+ <span class="n">seeders</span> <span class="o">=</span> <span class="n">get_torznab_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;seeders&#39;</span><span class="p">)</span>
+ <span class="n">leechers</span> <span class="o">=</span> <span class="n">get_torznab_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;leechers&#39;</span><span class="p">)</span>
+ <span class="n">peers</span> <span class="o">=</span> <span class="n">get_torznab_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;peers&#39;</span><span class="p">)</span>
+
+ <span class="c1"># map attributes to searx result</span>
+ <span class="n">result</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;torrent.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;filesize&#39;</span><span class="p">:</span> <span class="n">humanize_bytes</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">filesize</span><span class="p">))</span> <span class="k">if</span> <span class="n">filesize</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;files&#39;</span><span class="p">:</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;files&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;seed&#39;</span><span class="p">:</span> <span class="n">seeders</span><span class="p">,</span>
+ <span class="s1">&#39;leech&#39;</span><span class="p">:</span> <span class="n">_map_leechers</span><span class="p">(</span><span class="n">leechers</span><span class="p">,</span> <span class="n">seeders</span><span class="p">,</span> <span class="n">peers</span><span class="p">),</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">_map_result_url</span><span class="p">(</span><span class="n">guid</span><span class="p">,</span> <span class="n">comments</span><span class="p">),</span>
+ <span class="s1">&#39;publishedDate&#39;</span><span class="p">:</span> <span class="n">_map_published_date</span><span class="p">(</span><span class="n">pubDate</span><span class="p">),</span>
+ <span class="s1">&#39;torrentfile&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;magnetlink&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">link</span> <span class="o">=</span> <span class="n">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;link&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">show_torrent_files</span><span class="p">:</span>
+ <span class="n">result</span><span class="p">[</span><span class="s1">&#39;torrentfile&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_map_torrent_file</span><span class="p">(</span><span class="n">link</span><span class="p">,</span> <span class="n">enclosure_url</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">show_magnet_links</span><span class="p">:</span>
+ <span class="n">magneturl</span> <span class="o">=</span> <span class="n">get_torznab_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;magneturl&#39;</span><span class="p">)</span>
+ <span class="n">result</span><span class="p">[</span><span class="s1">&#39;magnetlink&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">_map_magnet_link</span><span class="p">(</span><span class="n">magneturl</span><span class="p">,</span> <span class="n">guid</span><span class="p">,</span> <span class="n">enclosure_url</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">result</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">_map_result_url</span><span class="p">(</span><span class="n">guid</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">comments</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">guid</span> <span class="ow">and</span> <span class="n">guid</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">guid</span>
+ <span class="k">if</span> <span class="n">comments</span> <span class="ow">and</span> <span class="n">comments</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">comments</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">_map_leechers</span><span class="p">(</span><span class="n">leechers</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">seeders</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">peers</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">leechers</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">leechers</span>
+ <span class="k">if</span> <span class="n">seeders</span> <span class="ow">and</span> <span class="n">peers</span><span class="p">:</span>
+ <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="n">peers</span><span class="p">)</span> <span class="o">-</span> <span class="nb">int</span><span class="p">(</span><span class="n">seeders</span><span class="p">))</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">_map_published_date</span><span class="p">(</span><span class="n">pubDate</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">datetime</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">pubDate</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">pubDate</span><span class="p">,</span> <span class="s1">&#39;</span><span class="si">%a</span><span class="s1">, </span><span class="si">%d</span><span class="s1"> %b %Y %H:%M:%S %z&#39;</span><span class="p">)</span>
+ <span class="k">except</span> <span class="p">(</span><span class="ne">ValueError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">)</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;ignore exception (publishedDate): </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">_map_torrent_file</span><span class="p">(</span><span class="n">link</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span> <span class="n">enclosure_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">link</span> <span class="ow">and</span> <span class="n">link</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">link</span>
+ <span class="k">if</span> <span class="n">enclosure_url</span> <span class="ow">and</span> <span class="n">enclosure_url</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">enclosure_url</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">def</span> <span class="nf">_map_magnet_link</span><span class="p">(</span>
+ <span class="n">magneturl</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="n">guid</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="n">enclosure_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="n">link</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">,</span>
+<span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">magneturl</span> <span class="ow">and</span> <span class="n">magneturl</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;magnet&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">magneturl</span>
+ <span class="k">if</span> <span class="n">guid</span> <span class="ow">and</span> <span class="n">guid</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;magnet&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">guid</span>
+ <span class="k">if</span> <span class="n">enclosure_url</span> <span class="ow">and</span> <span class="n">enclosure_url</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;magnet&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">enclosure_url</span>
+ <span class="k">if</span> <span class="n">link</span> <span class="ow">and</span> <span class="n">link</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;magnet&#39;</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">link</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<div class="viewcode-block" id="get_attribute">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.get_attribute">[docs]</a>
+<span class="k">def</span> <span class="nf">get_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span><span class="p">,</span> <span class="n">property_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get attribute from item.&quot;&quot;&quot;</span>
+ <span class="n">property_element</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">property_name</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">property_element</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">property_element</span><span class="o">.</span><span class="n">text</span>
+ <span class="k">return</span> <span class="kc">None</span></div>
+
+
+
+<div class="viewcode-block" id="get_torznab_attribute">
+<a class="viewcode-back" href="../../../dev/engines/online/torznab.html#searx.engines.torznab.get_torznab_attribute">[docs]</a>
+<span class="k">def</span> <span class="nf">get_torznab_attribute</span><span class="p">(</span><span class="n">item</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span><span class="p">,</span> <span class="n">attribute_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get torznab special attribute from item.&quot;&quot;&quot;</span>
+ <span class="n">element</span><span class="p">:</span> <span class="n">etree</span><span class="o">.</span><span class="n">Element</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="n">item</span><span class="o">.</span><span class="n">find</span><span class="p">(</span>
+ <span class="s1">&#39;.//torznab:attr[@name=&quot;</span><span class="si">{attribute_name}</span><span class="s1">&quot;]&#39;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">attribute_name</span><span class="o">=</span><span class="n">attribute_name</span><span class="p">),</span>
+ <span class="p">{</span><span class="s1">&#39;torznab&#39;</span><span class="p">:</span> <span class="s1">&#39;http://torznab.com/schemas/2015/feed&#39;</span><span class="p">},</span>
+ <span class="p">)</span>
+ <span class="k">if</span> <span class="n">element</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">element</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+ <span class="k">return</span> <span class="kc">None</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/voidlinux.html b/_modules/searx/engines/voidlinux.html
new file mode 100644
index 000000000..3bd8f7ef0
--- /dev/null
+++ b/_modules/searx/engines/voidlinux.html
@@ -0,0 +1,201 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.voidlinux &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.voidlinux</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.voidlinux</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;SearXNG engine for `Void Linux binary packages`_. Void is a general purpose</span>
+<span class="sd">operating system, based on the monolithic Linux kernel. Its package system</span>
+<span class="sd">allows you to quickly install, update and remove software; software is provided</span>
+<span class="sd">in binary packages or can be built directly from sources with the help of the</span>
+<span class="sd">XBPS source packages collection.</span>
+
+<span class="sd">.. _Void Linux binary packages: https://voidlinux.org/packages/</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">re</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote_plus</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">humanize_bytes</span>
+
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;website&#39;</span><span class="p">:</span> <span class="s1">&#39;https://voidlinux.org/packages/&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;wikidata_id&#39;</span><span class="p">:</span> <span class="s1">&#39;Q19310966&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;use_official_api&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s1">&#39;official_api_documentation&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s1">&#39;require_api_key&#39;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s1">&#39;results&#39;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;packages&#39;</span><span class="p">,</span> <span class="s1">&#39;it&#39;</span><span class="p">]</span>
+
+<span class="n">base_url</span> <span class="o">=</span> <span class="s2">&quot;https://xq-api.voidlinux.org&quot;</span>
+<span class="n">pkg_repo_url</span> <span class="o">=</span> <span class="s2">&quot;https://github.com/void-linux/void-packages&quot;</span>
+
+<span class="n">void_arch</span> <span class="o">=</span> <span class="s1">&#39;x86_64&#39;</span>
+<span class="sd">&quot;&quot;&quot;Default architecture to search for. For valid values see :py:obj:`ARCH_RE`&quot;&quot;&quot;</span>
+
+<span class="n">ARCH_RE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s1">&#39;aarch64-musl|armv6l-musl|armv7l-musl|x86_64-musl|aarch64|armv6l|armv7l|i686|x86_64&#39;</span><span class="p">)</span>
+<span class="sd">&quot;&quot;&quot;Regular expression that match a architecture in the query string.&quot;&quot;&quot;</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+ <span class="n">arch_path</span> <span class="o">=</span> <span class="n">ARCH_RE</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">arch_path</span><span class="p">:</span>
+ <span class="n">arch_path</span> <span class="o">=</span> <span class="n">arch_path</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">arch_path</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">arch_path</span> <span class="o">=</span> <span class="n">void_arch</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">/v1/query/</span><span class="si">{</span><span class="n">arch_path</span><span class="si">}</span><span class="s2">?q=</span><span class="si">{</span><span class="n">quote_plus</span><span class="p">(</span><span class="n">query</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/void.html#searx.engines.voidlinux.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
+<span class="sd"> At Void Linux, several packages sometimes share the same source code</span>
+<span class="sd"> (template) and therefore also have the same URL. Results with identical</span>
+<span class="sd"> URLs are merged as one result for SearXNG.</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">packages</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()[</span><span class="s1">&#39;data&#39;</span><span class="p">]:</span>
+
+ <span class="c1"># 32bit and dbg packages don&#39;t have their own package templates</span>
+ <span class="n">github_slug</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">sub</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;-(32bit|dbg)$&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">])</span>
+ <span class="n">pkg_url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">pkg_repo_url</span><span class="si">}</span><span class="s2">/tree/master/srcpkgs/</span><span class="si">{</span><span class="n">github_slug</span><span class="si">}</span><span class="s2">&quot;</span>
+
+ <span class="n">pkg_list</span> <span class="o">=</span> <span class="n">packages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">pkg_url</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="n">pkg_list</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;short_desc&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="n">humanize_bytes</span><span class="p">(</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;filename_size&#39;</span><span class="p">])</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
+ <span class="s1">&#39;package_name&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;v</span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;version&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">_</span><span class="si">{</span><span class="n">result</span><span class="p">[</span><span class="s1">&#39;revision&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
+ <span class="s1">&#39;tags&#39;</span><span class="p">:</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;repository&#39;</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="n">packages</span><span class="p">[</span><span class="n">pkg_url</span><span class="p">]</span> <span class="o">=</span> <span class="n">pkg_list</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">for</span> <span class="n">pkg_url</span><span class="p">,</span> <span class="n">pkg_list</span> <span class="ow">in</span> <span class="n">packages</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">pkg_url</span><span class="p">,</span>
+ <span class="s1">&#39;template&#39;</span><span class="p">:</span> <span class="s1">&#39;packages.html&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="s1">&#39;title&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">pkg_list</span><span class="p">),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">pkg_list</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;content&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;package_name&#39;</span><span class="p">:</span> <span class="s1">&#39; | &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="s1">&#39;package_name&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">pkg_list</span><span class="p">),</span>
+ <span class="s1">&#39;version&#39;</span><span class="p">:</span> <span class="n">pkg_list</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;version&#39;</span><span class="p">],</span>
+ <span class="s1">&#39;tags&#39;</span><span class="p">:</span> <span class="p">[</span><span class="n">x</span><span class="p">[</span><span class="s1">&#39;tags&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">pkg_list</span><span class="p">],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/wikidata.html b/_modules/searx/engines/wikidata.html
new file mode 100644
index 000000000..7d4e942fe
--- /dev/null
+++ b/_modules/searx/engines/wikidata.html
@@ -0,0 +1,910 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.wikidata &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.wikidata</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.wikidata</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This module implements the Wikidata engine. Some implementations are shared</span>
+<span class="sd">from :ref:`wikipedia engine`.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="c1"># pylint: disable=missing-class-docstring</span>
+
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">hashlib</span> <span class="kn">import</span> <span class="n">md5</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span><span class="p">,</span> <span class="n">unquote</span>
+<span class="kn">from</span> <span class="nn">json</span> <span class="kn">import</span> <span class="n">loads</span>
+
+<span class="kn">from</span> <span class="nn">dateutil.parser</span> <span class="kn">import</span> <span class="n">isoparse</span>
+<span class="kn">from</span> <span class="nn">babel.dates</span> <span class="kn">import</span> <span class="n">format_datetime</span><span class="p">,</span> <span class="n">format_date</span><span class="p">,</span> <span class="n">format_time</span><span class="p">,</span> <span class="n">get_datetime_format</span>
+
+<span class="kn">from</span> <span class="nn">searx.data</span> <span class="kn">import</span> <span class="n">WIKIDATA_UNITS</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">post</span><span class="p">,</span> <span class="n">get</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">searx_useragent</span><span class="p">,</span> <span class="n">get_string_replaces_function</span>
+<span class="kn">from</span> <span class="nn">searx.external_urls</span> <span class="kn">import</span> <span class="n">get_external_url</span><span class="p">,</span> <span class="n">get_earth_coordinates_url</span><span class="p">,</span> <span class="n">area_to_osm_zoom</span>
+<span class="kn">from</span> <span class="nn">searx.engines.wikipedia</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">fetch_wikimedia_traits</span><span class="p">,</span>
+ <span class="n">get_wiki_params</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://wikidata.org/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q2013&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://query.wikidata.org/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">display_type</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;infobox&quot;</span><span class="p">]</span>
+<span class="sd">&quot;&quot;&quot;A list of display types composed from ``infobox`` and ``list``. The latter</span>
+<span class="sd">one will add a hit to the result list. The first one will show a hit in the</span>
+<span class="sd">info box. Both values can be set, or one of the two can be set.&quot;&quot;&quot;</span>
+
+
+<span class="c1"># SPARQL</span>
+<span class="n">SPARQL_ENDPOINT_URL</span> <span class="o">=</span> <span class="s1">&#39;https://query.wikidata.org/sparql&#39;</span>
+<span class="n">SPARQL_EXPLAIN_URL</span> <span class="o">=</span> <span class="s1">&#39;https://query.wikidata.org/bigdata/namespace/wdq/sparql?explain&#39;</span>
+<span class="n">WIKIDATA_PROPERTIES</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;P434&#39;</span><span class="p">:</span> <span class="s1">&#39;MusicBrainz&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P435&#39;</span><span class="p">:</span> <span class="s1">&#39;MusicBrainz&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P436&#39;</span><span class="p">:</span> <span class="s1">&#39;MusicBrainz&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P966&#39;</span><span class="p">:</span> <span class="s1">&#39;MusicBrainz&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P345&#39;</span><span class="p">:</span> <span class="s1">&#39;IMDb&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P2397&#39;</span><span class="p">:</span> <span class="s1">&#39;YouTube&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P1651&#39;</span><span class="p">:</span> <span class="s1">&#39;YouTube&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P2002&#39;</span><span class="p">:</span> <span class="s1">&#39;Twitter&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P2013&#39;</span><span class="p">:</span> <span class="s1">&#39;Facebook&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;P2003&#39;</span><span class="p">:</span> <span class="s1">&#39;Instagram&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># SERVICE wikibase:mwapi : https://www.mediawiki.org/wiki/Wikidata_Query_Service/User_Manual/MWAPI</span>
+<span class="c1"># SERVICE wikibase:label: https://en.wikibooks.org/wiki/SPARQL/SERVICE_-_Label#Manual_Label_SERVICE</span>
+<span class="c1"># https://en.wikibooks.org/wiki/SPARQL/WIKIDATA_Precision,_Units_and_Coordinates</span>
+<span class="c1"># https://www.mediawiki.org/wiki/Wikibase/Indexing/RDF_Dump_Format#Data_model</span>
+<span class="c1"># optimization:</span>
+<span class="c1"># * https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service/query_optimization</span>
+<span class="c1"># * https://github.com/blazegraph/database/wiki/QueryHints</span>
+<span class="n">QUERY_TEMPLATE</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
+<span class="s2">SELECT ?item ?itemLabel ?itemDescription ?lat ?long %SELECT%</span>
+<span class="s2">WHERE</span>
+<span class="s2">{</span>
+<span class="s2"> SERVICE wikibase:mwapi {</span>
+<span class="s2"> bd:serviceParam wikibase:endpoint &quot;www.wikidata.org&quot;;</span>
+<span class="s2"> wikibase:api &quot;EntitySearch&quot;;</span>
+<span class="s2"> wikibase:limit 1;</span>
+<span class="s2"> mwapi:search &quot;%QUERY%&quot;;</span>
+<span class="s2"> mwapi:language &quot;%LANGUAGE%&quot;.</span>
+<span class="s2"> ?item wikibase:apiOutputItem mwapi:item.</span>
+<span class="s2"> }</span>
+<span class="s2"> hint:Prior hint:runFirst &quot;true&quot;.</span>
+
+<span class="s2"> %WHERE%</span>
+
+<span class="s2"> SERVICE wikibase:label {</span>
+<span class="s2"> bd:serviceParam wikibase:language &quot;%LANGUAGE%,en&quot;.</span>
+<span class="s2"> ?item rdfs:label ?itemLabel .</span>
+<span class="s2"> ?item schema:description ?itemDescription .</span>
+<span class="s2"> %WIKIBASE_LABELS%</span>
+<span class="s2"> }</span>
+
+<span class="s2">}</span>
+<span class="s2">GROUP BY ?item ?itemLabel ?itemDescription ?lat ?long </span><span class="si">%G</span><span class="s2">ROUP_BY%</span>
+<span class="s2">&quot;&quot;&quot;</span>
+
+<span class="c1"># Get the calendar names and the property names</span>
+<span class="n">QUERY_PROPERTY_NAMES</span> <span class="o">=</span> <span class="s2">&quot;&quot;&quot;</span>
+<span class="s2">SELECT ?item ?name</span>
+<span class="s2">WHERE {</span>
+<span class="s2"> {</span>
+<span class="s2"> SELECT ?item</span>
+<span class="s2"> WHERE { ?item wdt:P279* wd:Q12132 }</span>
+<span class="s2"> } UNION {</span>
+<span class="s2"> VALUES ?item { %ATTRIBUTES% }</span>
+<span class="s2"> }</span>
+<span class="s2"> OPTIONAL { ?item rdfs:label ?name. }</span>
+<span class="s2">}</span>
+<span class="s2">&quot;&quot;&quot;</span>
+
+<span class="c1"># see the property &quot;dummy value&quot; of https://www.wikidata.org/wiki/Q2013 (Wikidata)</span>
+<span class="c1"># hard coded here to avoid to an additional SPARQL request when the server starts</span>
+<span class="n">DUMMY_ENTITY_URLS</span> <span class="o">=</span> <span class="nb">set</span><span class="p">(</span>
+ <span class="s2">&quot;http://www.wikidata.org/entity/&quot;</span> <span class="o">+</span> <span class="n">wid</span> <span class="k">for</span> <span class="n">wid</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;Q4115189&quot;</span><span class="p">,</span> <span class="s2">&quot;Q13406268&quot;</span><span class="p">,</span> <span class="s2">&quot;Q15397819&quot;</span><span class="p">,</span> <span class="s2">&quot;Q17339402&quot;</span><span class="p">)</span>
+<span class="p">)</span>
+
+
+<span class="c1"># https://www.w3.org/TR/sparql11-query/#rSTRING_LITERAL1</span>
+<span class="c1"># https://lists.w3.org/Archives/Public/public-rdf-dawg/2011OctDec/0175.html</span>
+<span class="n">sparql_string_escape</span> <span class="o">=</span> <span class="n">get_string_replaces_function</span><span class="p">(</span>
+ <span class="c1"># fmt: off</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;</span><span class="se">\t</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\t</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\n</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\n</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\r</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\r</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\b</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\b</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\f</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\f</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\&quot;</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\&quot;</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\&#39;</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\&#39;</span><span class="s1">&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;</span><span class="se">\\</span><span class="s1">&#39;</span><span class="p">:</span> <span class="s1">&#39;</span><span class="se">\\\\</span><span class="s1">&#39;</span>
+ <span class="p">}</span>
+ <span class="c1"># fmt: on</span>
+<span class="p">)</span>
+
+<span class="n">replace_http_by_https</span> <span class="o">=</span> <span class="n">get_string_replaces_function</span><span class="p">({</span><span class="s1">&#39;http:&#39;</span><span class="p">:</span> <span class="s1">&#39;https:&#39;</span><span class="p">})</span>
+
+
+<span class="k">def</span> <span class="nf">get_headers</span><span class="p">():</span>
+ <span class="c1"># user agent: https://www.mediawiki.org/wiki/Wikidata_Query_Service/User_Manual#Query_limits</span>
+ <span class="k">return</span> <span class="p">{</span><span class="s1">&#39;Accept&#39;</span><span class="p">:</span> <span class="s1">&#39;application/sparql-results+json&#39;</span><span class="p">,</span> <span class="s1">&#39;User-Agent&#39;</span><span class="p">:</span> <span class="n">searx_useragent</span><span class="p">()}</span>
+
+
+<span class="k">def</span> <span class="nf">get_label_for_entity</span><span class="p">(</span><span class="n">entity_id</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">WIKIDATA_PROPERTIES</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">entity_id</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">WIKIDATA_PROPERTIES</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">entity_id</span><span class="p">,</span> <span class="n">language</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">WIKIDATA_PROPERTIES</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">entity_id</span><span class="p">,</span> <span class="n">language</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]))</span>
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">WIKIDATA_PROPERTIES</span><span class="o">.</span><span class="n">get</span><span class="p">((</span><span class="n">entity_id</span><span class="p">,</span> <span class="s1">&#39;en&#39;</span><span class="p">))</span>
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">entity_id</span>
+ <span class="k">return</span> <span class="n">name</span>
+
+
+<span class="k">def</span> <span class="nf">send_wikidata_query</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s1">&#39;GET&#39;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;GET&#39;</span><span class="p">:</span>
+ <span class="c1"># query will be cached by wikidata</span>
+ <span class="n">http_response</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">SPARQL_ENDPOINT_URL</span> <span class="o">+</span> <span class="s1">&#39;?&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">}),</span> <span class="n">headers</span><span class="o">=</span><span class="n">get_headers</span><span class="p">())</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="c1"># query won&#39;t be cached by wikidata</span>
+ <span class="n">http_response</span> <span class="o">=</span> <span class="n">post</span><span class="p">(</span><span class="n">SPARQL_ENDPOINT_URL</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">},</span> <span class="n">headers</span><span class="o">=</span><span class="n">get_headers</span><span class="p">())</span>
+ <span class="k">if</span> <span class="n">http_response</span><span class="o">.</span><span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;SPARQL endpoint error </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">http_response</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;request time </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">http_response</span><span class="o">.</span><span class="n">elapsed</span><span class="p">))</span>
+ <span class="n">http_response</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
+ <span class="k">return</span> <span class="n">loads</span><span class="p">(</span><span class="n">http_response</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+
+ <span class="n">eng_tag</span><span class="p">,</span> <span class="n">_wiki_netloc</span> <span class="o">=</span> <span class="n">get_wiki_params</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="p">)</span>
+ <span class="n">query</span><span class="p">,</span> <span class="n">attributes</span> <span class="o">=</span> <span class="n">get_query</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">)</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;request --&gt; language </span><span class="si">%s</span><span class="s2"> // len(attributes): </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">attributes</span><span class="p">))</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;POST&#39;</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">SPARQL_ENDPOINT_URL</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">}</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">get_headers</span><span class="p">()</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;attributes&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">attributes</span>
+
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">jsonresponse</span> <span class="o">=</span> <span class="n">loads</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">())</span>
+
+ <span class="n">language</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span>
+ <span class="n">attributes</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">search_params</span><span class="p">[</span><span class="s1">&#39;attributes&#39;</span><span class="p">]</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;request --&gt; language </span><span class="si">%s</span><span class="s2"> // len(attributes): </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">language</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">attributes</span><span class="p">))</span>
+
+ <span class="n">seen_entities</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">jsonresponse</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;results&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;bindings&#39;</span><span class="p">,</span> <span class="p">[]):</span>
+ <span class="n">attribute_result</span> <span class="o">=</span> <span class="p">{</span><span class="n">key</span><span class="p">:</span> <span class="n">value</span><span class="p">[</span><span class="s1">&#39;value&#39;</span><span class="p">]</span> <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">result</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
+ <span class="n">entity_url</span> <span class="o">=</span> <span class="n">attribute_result</span><span class="p">[</span><span class="s1">&#39;item&#39;</span><span class="p">]</span>
+ <span class="k">if</span> <span class="n">entity_url</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">seen_entities</span> <span class="ow">and</span> <span class="n">entity_url</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">DUMMY_ENTITY_URLS</span><span class="p">:</span>
+ <span class="n">seen_entities</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">entity_url</span><span class="p">)</span>
+ <span class="n">results</span> <span class="o">+=</span> <span class="n">get_results</span><span class="p">(</span><span class="n">attribute_result</span><span class="p">,</span> <span class="n">attributes</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;The SPARQL request returns duplicate entities: </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">attribute_result</span><span class="p">))</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="n">_IMG_SRC_DEFAULT_URL_PREFIX</span> <span class="o">=</span> <span class="s2">&quot;https://commons.wikimedia.org/wiki/Special:FilePath/&quot;</span>
+<span class="n">_IMG_SRC_NEW_URL_PREFIX</span> <span class="o">=</span> <span class="s2">&quot;https://upload.wikimedia.org/wikipedia/commons/thumb/&quot;</span>
+
+
+<div class="viewcode-block" id="get_thumbnail">
+<a class="viewcode-back" href="../../../dev/engines/online/wikipedia.html#searx.engines.wikidata.get_thumbnail">[docs]</a>
+<span class="k">def</span> <span class="nf">get_thumbnail</span><span class="p">(</span><span class="n">img_src</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Get Thumbnail image from wikimedia commons</span>
+
+<span class="sd"> Images from commons.wikimedia.org are (HTTP) redirected to</span>
+<span class="sd"> upload.wikimedia.org. The redirected URL can be calculated by this</span>
+<span class="sd"> function.</span>
+
+<span class="sd"> - https://stackoverflow.com/a/33691240</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;get_thumbnail(): </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">img_src</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">img_src</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">_IMG_SRC_DEFAULT_URL_PREFIX</span> <span class="ow">in</span> <span class="n">img_src</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]:</span>
+ <span class="n">img_src_name</span> <span class="o">=</span> <span class="n">unquote</span><span class="p">(</span><span class="n">img_src</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">_IMG_SRC_DEFAULT_URL_PREFIX</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;?&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;%20&quot;</span><span class="p">,</span> <span class="s2">&quot;_&quot;</span><span class="p">))</span>
+ <span class="n">img_src_name_first</span> <span class="o">=</span> <span class="n">img_src_name</span>
+ <span class="n">img_src_name_second</span> <span class="o">=</span> <span class="n">img_src_name</span>
+
+ <span class="k">if</span> <span class="s2">&quot;.svg&quot;</span> <span class="ow">in</span> <span class="n">img_src_name</span><span class="o">.</span><span class="n">split</span><span class="p">()[</span><span class="mi">0</span><span class="p">]:</span>
+ <span class="n">img_src_name_second</span> <span class="o">=</span> <span class="n">img_src_name</span> <span class="o">+</span> <span class="s2">&quot;.png&quot;</span>
+
+ <span class="n">img_src_size</span> <span class="o">=</span> <span class="n">img_src</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">_IMG_SRC_DEFAULT_URL_PREFIX</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;?&quot;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span>
+ <span class="n">img_src_size</span> <span class="o">=</span> <span class="n">img_src_size</span><span class="p">[</span><span class="n">img_src_size</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;=&quot;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">:</span> <span class="n">img_src_size</span><span class="o">.</span><span class="n">index</span><span class="p">(</span><span class="s2">&quot;&amp;&quot;</span><span class="p">)]</span>
+ <span class="n">img_src_name_md5</span> <span class="o">=</span> <span class="n">md5</span><span class="p">(</span><span class="n">img_src_name</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">&quot;utf-8&quot;</span><span class="p">))</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">()</span>
+ <span class="n">img_src</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">_IMG_SRC_NEW_URL_PREFIX</span>
+ <span class="o">+</span> <span class="n">img_src_name_md5</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s2">&quot;/&quot;</span>
+ <span class="o">+</span> <span class="n">img_src_name_md5</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">2</span><span class="p">]</span>
+ <span class="o">+</span> <span class="s2">&quot;/&quot;</span>
+ <span class="o">+</span> <span class="n">img_src_name_first</span>
+ <span class="o">+</span> <span class="s2">&quot;/&quot;</span>
+ <span class="o">+</span> <span class="n">img_src_size</span>
+ <span class="o">+</span> <span class="s2">&quot;px-&quot;</span>
+ <span class="o">+</span> <span class="n">img_src_name_second</span>
+ <span class="p">)</span>
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s1">&#39;get_thumbnail() redirected: </span><span class="si">%s</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">img_src</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">img_src</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">get_results</span><span class="p">(</span><span class="n">attribute_result</span><span class="p">,</span> <span class="n">attributes</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="c1"># pylint: disable=too-many-branches</span>
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">infobox_title</span> <span class="o">=</span> <span class="n">attribute_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;itemLabel&#39;</span><span class="p">)</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">attribute_result</span><span class="p">[</span><span class="s1">&#39;item&#39;</span><span class="p">]</span>
+ <span class="n">infobox_id_lang</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">infobox_urls</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">infobox_attributes</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">infobox_content</span> <span class="o">=</span> <span class="n">attribute_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;itemDescription&#39;</span><span class="p">,</span> <span class="p">[])</span>
+ <span class="n">img_src</span> <span class="o">=</span> <span class="kc">None</span>
+ <span class="n">img_src_priority</span> <span class="o">=</span> <span class="mi">0</span>
+
+ <span class="k">for</span> <span class="n">attribute</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">attribute</span><span class="o">.</span><span class="n">get_str</span><span class="p">(</span><span class="n">attribute_result</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="n">attribute_type</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">attribute</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">attribute_type</span> <span class="ow">in</span> <span class="p">(</span><span class="n">WDURLAttribute</span><span class="p">,</span> <span class="n">WDArticle</span><span class="p">):</span>
+ <span class="c1"># get_select() method : there is group_concat(distinct ...;separator=&quot;, &quot;)</span>
+ <span class="c1"># split the value here</span>
+ <span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;, &#39;</span><span class="p">):</span>
+ <span class="n">infobox_urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">attribute</span><span class="o">.</span><span class="n">get_label</span><span class="p">(</span><span class="n">language</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="o">**</span><span class="n">attribute</span><span class="o">.</span><span class="n">kwargs</span><span class="p">})</span>
+ <span class="c1"># &quot;normal&quot; results (not infobox) include official website and Wikipedia links.</span>
+ <span class="k">if</span> <span class="s2">&quot;list&quot;</span> <span class="ow">in</span> <span class="n">display_type</span> <span class="ow">and</span> <span class="p">(</span><span class="n">attribute</span><span class="o">.</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;official&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">attribute_type</span> <span class="o">==</span> <span class="n">WDArticle</span><span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">infobox_title</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s2">&quot;content&quot;</span><span class="p">:</span> <span class="n">infobox_content</span><span class="p">})</span>
+
+ <span class="c1"># update the infobox_id with the wikipedia URL</span>
+ <span class="c1"># first the local wikipedia URL, and as fallback the english wikipedia URL</span>
+ <span class="k">if</span> <span class="n">attribute_type</span> <span class="o">==</span> <span class="n">WDArticle</span> <span class="ow">and</span> <span class="p">(</span>
+ <span class="p">(</span><span class="n">attribute</span><span class="o">.</span><span class="n">language</span> <span class="o">==</span> <span class="s1">&#39;en&#39;</span> <span class="ow">and</span> <span class="n">infobox_id_lang</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">or</span> <span class="n">attribute</span><span class="o">.</span><span class="n">language</span> <span class="o">!=</span> <span class="s1">&#39;en&#39;</span>
+ <span class="p">):</span>
+ <span class="n">infobox_id_lang</span> <span class="o">=</span> <span class="n">attribute</span><span class="o">.</span><span class="n">language</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">url</span>
+ <span class="k">elif</span> <span class="n">attribute_type</span> <span class="o">==</span> <span class="n">WDImageAttribute</span><span class="p">:</span>
+ <span class="c1"># this attribute is an image.</span>
+ <span class="c1"># replace the current image only the priority is lower</span>
+ <span class="c1"># (the infobox contain only one image).</span>
+ <span class="k">if</span> <span class="n">attribute</span><span class="o">.</span><span class="n">priority</span> <span class="o">&gt;</span> <span class="n">img_src_priority</span><span class="p">:</span>
+ <span class="n">img_src</span> <span class="o">=</span> <span class="n">get_thumbnail</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="n">img_src_priority</span> <span class="o">=</span> <span class="n">attribute</span><span class="o">.</span><span class="n">priority</span>
+ <span class="k">elif</span> <span class="n">attribute_type</span> <span class="o">==</span> <span class="n">WDGeoAttribute</span><span class="p">:</span>
+ <span class="c1"># geocoordinate link</span>
+ <span class="c1"># use the area to get the OSM zoom</span>
+ <span class="c1"># Note: ignore the unit (must be km² otherwise the calculation is wrong)</span>
+ <span class="c1"># Should use normalized value p:P2046/psn:P2046/wikibase:quantityAmount</span>
+ <span class="n">area</span> <span class="o">=</span> <span class="n">attribute_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;P2046&#39;</span><span class="p">)</span>
+ <span class="n">osm_zoom</span> <span class="o">=</span> <span class="n">area_to_osm_zoom</span><span class="p">(</span><span class="n">area</span><span class="p">)</span> <span class="k">if</span> <span class="n">area</span> <span class="k">else</span> <span class="mi">19</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">attribute</span><span class="o">.</span><span class="n">get_geo_url</span><span class="p">(</span><span class="n">attribute_result</span><span class="p">,</span> <span class="n">osm_zoom</span><span class="o">=</span><span class="n">osm_zoom</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">url</span><span class="p">:</span>
+ <span class="n">infobox_urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">attribute</span><span class="o">.</span><span class="n">get_label</span><span class="p">(</span><span class="n">language</span><span class="p">),</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;entity&#39;</span><span class="p">:</span> <span class="n">attribute</span><span class="o">.</span><span class="n">name</span><span class="p">})</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">infobox_attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span><span class="s1">&#39;label&#39;</span><span class="p">:</span> <span class="n">attribute</span><span class="o">.</span><span class="n">get_label</span><span class="p">(</span><span class="n">language</span><span class="p">),</span> <span class="s1">&#39;value&#39;</span><span class="p">:</span> <span class="n">value</span><span class="p">,</span> <span class="s1">&#39;entity&#39;</span><span class="p">:</span> <span class="n">attribute</span><span class="o">.</span><span class="n">name</span><span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">infobox_id</span><span class="p">:</span>
+ <span class="n">infobox_id</span> <span class="o">=</span> <span class="n">replace_http_by_https</span><span class="p">(</span><span class="n">infobox_id</span><span class="p">)</span>
+
+ <span class="c1"># add the wikidata URL at the end</span>
+ <span class="n">infobox_urls</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="s1">&#39;Wikidata&#39;</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">attribute_result</span><span class="p">[</span><span class="s1">&#39;item&#39;</span><span class="p">]})</span>
+
+ <span class="k">if</span> <span class="p">(</span>
+ <span class="s2">&quot;list&quot;</span> <span class="ow">in</span> <span class="n">display_type</span>
+ <span class="ow">and</span> <span class="n">img_src</span> <span class="ow">is</span> <span class="kc">None</span>
+ <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">infobox_attributes</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
+ <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">infobox_urls</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span>
+ <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">infobox_content</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span>
+ <span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">infobox_urls</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="s1">&#39;url&#39;</span><span class="p">],</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">infobox_title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">infobox_content</span><span class="p">})</span>
+ <span class="k">elif</span> <span class="s2">&quot;infobox&quot;</span> <span class="ow">in</span> <span class="n">display_type</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;infobox&#39;</span><span class="p">:</span> <span class="n">infobox_title</span><span class="p">,</span>
+ <span class="s1">&#39;id&#39;</span><span class="p">:</span> <span class="n">infobox_id</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">infobox_content</span><span class="p">,</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">img_src</span><span class="p">,</span>
+ <span class="s1">&#39;urls&#39;</span><span class="p">:</span> <span class="n">infobox_urls</span><span class="p">,</span>
+ <span class="s1">&#39;attributes&#39;</span><span class="p">:</span> <span class="n">infobox_attributes</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="k">def</span> <span class="nf">get_query</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">attributes</span> <span class="o">=</span> <span class="n">get_attributes</span><span class="p">(</span><span class="n">language</span><span class="p">)</span>
+ <span class="n">select</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">get_select</span><span class="p">()</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">]</span>
+ <span class="n">where</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">get_where</span><span class="p">()</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">]))</span>
+ <span class="n">wikibase_label</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">get_wikibase_label</span><span class="p">()</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">]))</span>
+ <span class="n">group_by</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="nb">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">,</span> <span class="p">[</span><span class="n">a</span><span class="o">.</span><span class="n">get_group_by</span><span class="p">()</span> <span class="k">for</span> <span class="n">a</span> <span class="ow">in</span> <span class="n">attributes</span><span class="p">]))</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">QUERY_TEMPLATE</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%QUERY%&#39;</span><span class="p">,</span> <span class="n">sparql_string_escape</span><span class="p">(</span><span class="n">query</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%SELECT%&#39;</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">select</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%WHERE%&#39;</span><span class="p">,</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1"> &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">where</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%WIKIBASE_LABELS%&#39;</span><span class="p">,</span> <span class="s1">&#39;</span><span class="se">\n</span><span class="s1"> &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">wikibase_label</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%G</span><span class="s1">ROUP_BY%&#39;</span><span class="p">,</span> <span class="s1">&#39; &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">group_by</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%LANGUAGE%&#39;</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+ <span class="p">)</span>
+ <span class="k">return</span> <span class="n">query</span><span class="p">,</span> <span class="n">attributes</span>
+
+
+<span class="k">def</span> <span class="nf">get_attributes</span><span class="p">(</span><span class="n">language</span><span class="p">):</span>
+ <span class="c1"># pylint: disable=too-many-statements</span>
+ <span class="n">attributes</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">def</span> <span class="nf">add_value</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
+
+ <span class="k">def</span> <span class="nf">add_amount</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDAmountAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
+
+ <span class="k">def</span> <span class="nf">add_label</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDLabelAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
+
+ <span class="k">def</span> <span class="nf">add_url</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDURLAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="p">,</span> <span class="n">kwargs</span><span class="p">))</span>
+
+ <span class="k">def</span> <span class="nf">add_image</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">1</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDImageAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="p">,</span> <span class="n">priority</span><span class="p">))</span>
+
+ <span class="k">def</span> <span class="nf">add_date</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDDateAttribute</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
+
+ <span class="c1"># Dates</span>
+ <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="s1">&#39;P571&#39;</span><span class="p">,</span> <span class="c1"># inception date</span>
+ <span class="s1">&#39;P576&#39;</span><span class="p">,</span> <span class="c1"># dissolution date</span>
+ <span class="s1">&#39;P580&#39;</span><span class="p">,</span> <span class="c1"># start date</span>
+ <span class="s1">&#39;P582&#39;</span><span class="p">,</span> <span class="c1"># end date</span>
+ <span class="s1">&#39;P569&#39;</span><span class="p">,</span> <span class="c1"># date of birth</span>
+ <span class="s1">&#39;P570&#39;</span><span class="p">,</span> <span class="c1"># date of death</span>
+ <span class="s1">&#39;P619&#39;</span><span class="p">,</span> <span class="c1"># date of spacecraft launch</span>
+ <span class="s1">&#39;P620&#39;</span><span class="p">,</span>
+ <span class="p">]:</span> <span class="c1"># date of spacecraft landing</span>
+ <span class="n">add_date</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="s1">&#39;P27&#39;</span><span class="p">,</span> <span class="c1"># country of citizenship</span>
+ <span class="s1">&#39;P495&#39;</span><span class="p">,</span> <span class="c1"># country of origin</span>
+ <span class="s1">&#39;P17&#39;</span><span class="p">,</span> <span class="c1"># country</span>
+ <span class="s1">&#39;P159&#39;</span><span class="p">,</span>
+ <span class="p">]:</span> <span class="c1"># headquarters location</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
+
+ <span class="c1"># Places</span>
+ <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="s1">&#39;P36&#39;</span><span class="p">,</span> <span class="c1"># capital</span>
+ <span class="s1">&#39;P35&#39;</span><span class="p">,</span> <span class="c1"># head of state</span>
+ <span class="s1">&#39;P6&#39;</span><span class="p">,</span> <span class="c1"># head of government</span>
+ <span class="s1">&#39;P122&#39;</span><span class="p">,</span> <span class="c1"># basic form of government</span>
+ <span class="s1">&#39;P37&#39;</span><span class="p">,</span>
+ <span class="p">]:</span> <span class="c1"># official language</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
+
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P1082&#39;</span><span class="p">)</span> <span class="c1"># population</span>
+ <span class="n">add_amount</span><span class="p">(</span><span class="s1">&#39;P2046&#39;</span><span class="p">)</span> <span class="c1"># area</span>
+ <span class="n">add_amount</span><span class="p">(</span><span class="s1">&#39;P281&#39;</span><span class="p">)</span> <span class="c1"># postal code</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P38&#39;</span><span class="p">)</span> <span class="c1"># currency</span>
+ <span class="n">add_amount</span><span class="p">(</span><span class="s1">&#39;P2048&#39;</span><span class="p">)</span> <span class="c1"># height (building)</span>
+
+ <span class="c1"># Media</span>
+ <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span>
+ <span class="s1">&#39;P400&#39;</span><span class="p">,</span> <span class="c1"># platform (videogames, computing)</span>
+ <span class="s1">&#39;P50&#39;</span><span class="p">,</span> <span class="c1"># author</span>
+ <span class="s1">&#39;P170&#39;</span><span class="p">,</span> <span class="c1"># creator</span>
+ <span class="s1">&#39;P57&#39;</span><span class="p">,</span> <span class="c1"># director</span>
+ <span class="s1">&#39;P175&#39;</span><span class="p">,</span> <span class="c1"># performer</span>
+ <span class="s1">&#39;P178&#39;</span><span class="p">,</span> <span class="c1"># developer</span>
+ <span class="s1">&#39;P162&#39;</span><span class="p">,</span> <span class="c1"># producer</span>
+ <span class="s1">&#39;P176&#39;</span><span class="p">,</span> <span class="c1"># manufacturer</span>
+ <span class="s1">&#39;P58&#39;</span><span class="p">,</span> <span class="c1"># screenwriter</span>
+ <span class="s1">&#39;P272&#39;</span><span class="p">,</span> <span class="c1"># production company</span>
+ <span class="s1">&#39;P264&#39;</span><span class="p">,</span> <span class="c1"># record label</span>
+ <span class="s1">&#39;P123&#39;</span><span class="p">,</span> <span class="c1"># publisher</span>
+ <span class="s1">&#39;P449&#39;</span><span class="p">,</span> <span class="c1"># original network</span>
+ <span class="s1">&#39;P750&#39;</span><span class="p">,</span> <span class="c1"># distributed by</span>
+ <span class="s1">&#39;P86&#39;</span><span class="p">,</span>
+ <span class="p">]:</span> <span class="c1"># composer</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>
+
+ <span class="n">add_date</span><span class="p">(</span><span class="s1">&#39;P577&#39;</span><span class="p">)</span> <span class="c1"># publication date</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P136&#39;</span><span class="p">)</span> <span class="c1"># genre (music, film, artistic...)</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P364&#39;</span><span class="p">)</span> <span class="c1"># original language</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P212&#39;</span><span class="p">)</span> <span class="c1"># ISBN-13</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P957&#39;</span><span class="p">)</span> <span class="c1"># ISBN-10</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P275&#39;</span><span class="p">)</span> <span class="c1"># copyright license</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P277&#39;</span><span class="p">)</span> <span class="c1"># programming language</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P348&#39;</span><span class="p">)</span> <span class="c1"># version</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P840&#39;</span><span class="p">)</span> <span class="c1"># narrative location</span>
+
+ <span class="c1"># Languages</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P1098&#39;</span><span class="p">)</span> <span class="c1"># number of speakers</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P282&#39;</span><span class="p">)</span> <span class="c1"># writing system</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P1018&#39;</span><span class="p">)</span> <span class="c1"># language regulatory body</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P218&#39;</span><span class="p">)</span> <span class="c1"># language code (ISO 639-1)</span>
+
+ <span class="c1"># Other</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P169&#39;</span><span class="p">)</span> <span class="c1"># ceo</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P112&#39;</span><span class="p">)</span> <span class="c1"># founded by</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P1454&#39;</span><span class="p">)</span> <span class="c1"># legal form (company, organization)</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P137&#39;</span><span class="p">)</span> <span class="c1"># operator (service, facility, ...)</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P1029&#39;</span><span class="p">)</span> <span class="c1"># crew members (tripulation)</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P225&#39;</span><span class="p">)</span> <span class="c1"># taxon name</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P274&#39;</span><span class="p">)</span> <span class="c1"># chemical formula</span>
+ <span class="n">add_label</span><span class="p">(</span><span class="s1">&#39;P1346&#39;</span><span class="p">)</span> <span class="c1"># winner (sports, contests, ...)</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P1120&#39;</span><span class="p">)</span> <span class="c1"># number of deaths</span>
+ <span class="n">add_value</span><span class="p">(</span><span class="s1">&#39;P498&#39;</span><span class="p">)</span> <span class="c1"># currency code (ISO 4217)</span>
+
+ <span class="c1"># URL</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P856&#39;</span><span class="p">,</span> <span class="n">official</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># official website</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDArticle</span><span class="p">(</span><span class="n">language</span><span class="p">))</span> <span class="c1"># wikipedia (user language)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">language</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">):</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDArticle</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">))</span> <span class="c1"># wikipedia (english)</span>
+
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P1324&#39;</span><span class="p">)</span> <span class="c1"># source code repository</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P1581&#39;</span><span class="p">)</span> <span class="c1"># blog</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P434&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;musicbrainz_artist&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P435&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;musicbrainz_work&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P436&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;musicbrainz_release_group&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P966&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;musicbrainz_label&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P345&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;imdb_id&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P2397&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;youtube_channel&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P1651&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;youtube_video&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P2002&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;twitter_profile&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P2013&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;facebook_profile&#39;</span><span class="p">)</span>
+ <span class="n">add_url</span><span class="p">(</span><span class="s1">&#39;P2003&#39;</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;instagram_profile&#39;</span><span class="p">)</span>
+
+ <span class="c1"># Map</span>
+ <span class="n">attributes</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">WDGeoAttribute</span><span class="p">(</span><span class="s1">&#39;P625&#39;</span><span class="p">))</span>
+
+ <span class="c1"># Image</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P15&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># route map</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P242&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># locator map</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P154&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># logo</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P18&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># image</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P41&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># flag</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P2716&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># collage</span>
+ <span class="n">add_image</span><span class="p">(</span><span class="s1">&#39;P2910&#39;</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">7</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="s1">&#39;wikimedia_image&#39;</span><span class="p">)</span> <span class="c1"># icon</span>
+
+ <span class="k">return</span> <span class="n">attributes</span>
+
+
+<span class="k">class</span> <span class="nc">WDAttribute</span><span class="p">:</span>
+ <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,)</span>
+
+ <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
+
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;(group_concat(distinct ?</span><span class="si">{name}</span><span class="s1">;separator=&quot;, &quot;) as ?</span><span class="si">{name}</span><span class="s1">s)&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_label</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">get_label_for_entity</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;OPTIONAL { ?item wdt:</span><span class="si">{name}</span><span class="s2"> ?</span><span class="si">{name}</span><span class="s2"> . }&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_wikibase_label</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">get_group_by</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+ <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;s&#39;</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="fm">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;&lt;&#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="vm">__name__</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;:&#39;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;&gt;&#39;</span>
+
+
+<span class="k">class</span> <span class="nc">WDAmountAttribute</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;?</span><span class="si">{name}</span><span class="s1"> ?</span><span class="si">{name}</span><span class="s1">Unit&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;&quot; OPTIONAL { ?item p:</span><span class="si">{name}</span><span class="s2"> ?</span><span class="si">{name}</span><span class="s2">Node .</span>
+<span class="s2"> ?</span><span class="si">{name}</span><span class="s2">Node rdf:type wikibase:BestRank ; ps:</span><span class="si">{name}</span><span class="s2"> ?</span><span class="si">{name}</span><span class="s2"> .</span>
+<span class="s2"> OPTIONAL { ?</span><span class="si">{name}</span><span class="s2">Node psv:</span><span class="si">{name}</span><span class="s2">/wikibase:quantityUnit ?</span><span class="si">{name}</span><span class="s2">Unit. } }&quot;&quot;&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span>
+ <span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
+ <span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_group_by</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_select</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+ <span class="n">unit</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s2">&quot;Unit&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">unit</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">unit</span> <span class="o">=</span> <span class="n">unit</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;http://www.wikidata.org/entity/&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="s2">&quot; &quot;</span> <span class="o">+</span> <span class="n">get_label_for_entity</span><span class="p">(</span><span class="n">unit</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+
+<span class="k">class</span> <span class="nc">WDArticle</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+
+ <span class="vm">__slots__</span> <span class="o">=</span> <span class="s1">&#39;language&#39;</span><span class="p">,</span> <span class="s1">&#39;kwargs&#39;</span>
+
+ <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">language</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
+ <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="s1">&#39;wikipedia&#39;</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">language</span> <span class="o">=</span> <span class="n">language</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span> <span class="ow">or</span> <span class="p">{}</span>
+
+ <span class="k">def</span> <span class="nf">get_label</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="c1"># language parameter is ignored</span>
+ <span class="k">return</span> <span class="s2">&quot;Wikipedia (</span><span class="si">{language}</span><span class="s2">)&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{language}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">language</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;?article</span><span class="si">{language}</span><span class="s2"> ?articleName</span><span class="si">{language}</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{language}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">language</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;&quot;OPTIONAL { ?article</span><span class="si">{language}</span><span class="s2"> schema:about ?item ;</span>
+<span class="s2"> schema:inLanguage &quot;</span><span class="si">{language}</span><span class="s2">&quot; ;</span>
+<span class="s2"> schema:isPartOf &lt;https://</span><span class="si">{language}</span><span class="s2">.wikipedia.org/&gt; ;</span>
+<span class="s2"> schema:name ?articleName</span><span class="si">{language}</span><span class="s2"> . }&quot;&quot;&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span>
+ <span class="s1">&#39;</span><span class="si">{language}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">language</span>
+ <span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_group_by</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_select</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">key</span> <span class="o">=</span> <span class="s1">&#39;article</span><span class="si">{language}</span><span class="s1">&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{language}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">language</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
+
+
+<span class="k">class</span> <span class="nc">WDLabelAttribute</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;(group_concat(distinct ?</span><span class="si">{name}</span><span class="s1">Label;separator=&quot;, &quot;) as ?</span><span class="si">{name}</span><span class="s1">Labels)&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;OPTIONAL { ?item wdt:</span><span class="si">{name}</span><span class="s2"> ?</span><span class="si">{name}</span><span class="s2"> . }&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_wikibase_label</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;?</span><span class="si">{name}</span><span class="s2"> rdfs:label ?</span><span class="si">{name}</span><span class="s2">Label .&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="k">return</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;Labels&#39;</span><span class="p">)</span>
+
+
+<span class="k">class</span> <span class="nc">WDURLAttribute</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+
+ <span class="n">HTTP_WIKIMEDIA_IMAGE</span> <span class="o">=</span> <span class="s1">&#39;http://commons.wikimedia.org/wiki/Special:FilePath/&#39;</span>
+
+ <span class="vm">__slots__</span> <span class="o">=</span> <span class="s1">&#39;url_id&#39;</span><span class="p">,</span> <span class="s1">&#39;kwargs&#39;</span>
+
+ <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
+ <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">url_id</span> <span class="o">=</span> <span class="n">url_id</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">kwargs</span> <span class="o">=</span> <span class="n">kwargs</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;s&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">url_id</span> <span class="ow">and</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">!=</span> <span class="s1">&#39;&#39;</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">url_id</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">url_id</span>
+ <span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="n">WDURLAttribute</span><span class="o">.</span><span class="n">HTTP_WIKIMEDIA_IMAGE</span><span class="p">):</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">value</span><span class="p">[</span><span class="nb">len</span><span class="p">(</span><span class="n">WDURLAttribute</span><span class="o">.</span><span class="n">HTTP_WIKIMEDIA_IMAGE</span><span class="p">)</span> <span class="p">:]</span>
+ <span class="n">url_id</span> <span class="o">=</span> <span class="s1">&#39;wikimedia_image&#39;</span>
+ <span class="k">return</span> <span class="n">get_external_url</span><span class="p">(</span><span class="n">url_id</span><span class="p">,</span> <span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+
+<span class="k">class</span> <span class="nc">WDGeoAttribute</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">get_label</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;OpenStreetMap&quot;</span>
+
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;?</span><span class="si">{name}</span><span class="s2">Lat ?</span><span class="si">{name}</span><span class="s2">Long&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;&quot;OPTIONAL { ?item p:</span><span class="si">{name}</span><span class="s2">/psv:</span><span class="si">{name}</span><span class="s2"> [</span>
+<span class="s2"> wikibase:geoLatitude ?</span><span class="si">{name}</span><span class="s2">Lat ;</span>
+<span class="s2"> wikibase:geoLongitude ?</span><span class="si">{name}</span><span class="s2">Long ] }&quot;&quot;&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span>
+ <span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
+ <span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_group_by</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_select</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">latitude</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;Lat&#39;</span><span class="p">)</span>
+ <span class="n">longitude</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;Long&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">latitude</span> <span class="ow">and</span> <span class="n">longitude</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">latitude</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="n">longitude</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+ <span class="k">def</span> <span class="nf">get_geo_url</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">osm_zoom</span><span class="o">=</span><span class="mi">19</span><span class="p">):</span>
+ <span class="n">latitude</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;Lat&#39;</span><span class="p">)</span>
+ <span class="n">longitude</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;Long&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">latitude</span> <span class="ow">and</span> <span class="n">longitude</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">get_earth_coordinates_url</span><span class="p">(</span><span class="n">latitude</span><span class="p">,</span> <span class="n">longitude</span><span class="p">,</span> <span class="n">osm_zoom</span><span class="p">)</span>
+ <span class="k">return</span> <span class="kc">None</span>
+
+
+<span class="k">class</span> <span class="nc">WDImageAttribute</span><span class="p">(</span><span class="n">WDURLAttribute</span><span class="p">):</span>
+
+ <span class="vm">__slots__</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;priority&#39;</span><span class="p">,)</span>
+
+ <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">priority</span><span class="o">=</span><span class="mi">100</span><span class="p">):</span>
+ <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">url_id</span><span class="p">)</span>
+ <span class="bp">self</span><span class="o">.</span><span class="n">priority</span> <span class="o">=</span> <span class="n">priority</span>
+
+
+<span class="k">class</span> <span class="nc">WDDateAttribute</span><span class="p">(</span><span class="n">WDAttribute</span><span class="p">):</span>
+ <span class="k">def</span> <span class="nf">get_select</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="s1">&#39;?</span><span class="si">{name}</span><span class="s1"> ?</span><span class="si">{name}</span><span class="s1">timePrecision ?</span><span class="si">{name}</span><span class="s1">timeZone ?</span><span class="si">{name}</span><span class="s1">timeCalendar&#39;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_where</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="c1"># To remove duplicate, add</span>
+ <span class="c1"># FILTER NOT EXISTS { ?item p:{name}/psv:{name}/wikibase:timeValue ?{name}bis FILTER (?{name}bis &lt; ?{name}) }</span>
+ <span class="c1"># this filter is too slow, so the response function ignore duplicate results</span>
+ <span class="c1"># (see the seen_entities variable)</span>
+ <span class="k">return</span> <span class="s2">&quot;&quot;&quot;OPTIONAL { ?item p:</span><span class="si">{name}</span><span class="s2">/psv:</span><span class="si">{name}</span><span class="s2"> [</span>
+<span class="s2"> wikibase:timeValue ?</span><span class="si">{name}</span><span class="s2"> ;</span>
+<span class="s2"> wikibase:timePrecision ?</span><span class="si">{name}</span><span class="s2">timePrecision ;</span>
+<span class="s2"> wikibase:timeTimezone ?</span><span class="si">{name}</span><span class="s2">timeZone ;</span>
+<span class="s2"> wikibase:timeCalendarModel ?</span><span class="si">{name}</span><span class="s2">timeCalendar ] . }</span>
+<span class="s2"> hint:Prior hint:rangeSafe true;&quot;&quot;&quot;</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span>
+ <span class="s1">&#39;</span><span class="si">{name}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
+ <span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">get_group_by</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
+ <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_select</span><span class="p">()</span>
+
+ <span class="k">def</span> <span class="nf">format_8</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+ <span class="c1"># precision: less than a year</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+ <span class="k">def</span> <span class="nf">format_9</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span>
+ <span class="n">year</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="c1"># precision: year</span>
+ <span class="k">if</span> <span class="n">year</span> <span class="o">&lt;</span> <span class="mi">1584</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">year</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">year</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span>
+ <span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">year</span><span class="p">)</span>
+ <span class="n">timestamp</span> <span class="o">=</span> <span class="n">isoparse</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">format_date</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;yyyy&#39;</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">format_10</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span>
+ <span class="c1"># precision: month</span>
+ <span class="n">timestamp</span> <span class="o">=</span> <span class="n">isoparse</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">format_date</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;MMMM y&#39;</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">format_11</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span>
+ <span class="c1"># precision: day</span>
+ <span class="n">timestamp</span> <span class="o">=</span> <span class="n">isoparse</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">format_date</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;full&#39;</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">format_13</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span>
+ <span class="n">timestamp</span> <span class="o">=</span> <span class="n">isoparse</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+ <span class="c1"># precision: minute</span>
+ <span class="k">return</span> <span class="p">(</span>
+ <span class="n">get_datetime_format</span><span class="p">(</span><span class="nb">format</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">)</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">&quot;&#39;&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">)</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{0}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">format_time</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="s1">&#39;full&#39;</span><span class="p">,</span> <span class="n">tzinfo</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">))</span>
+ <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">{1}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">format_date</span><span class="p">(</span><span class="n">timestamp</span><span class="p">,</span> <span class="s1">&#39;short&#39;</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">))</span>
+ <span class="p">)</span>
+
+ <span class="k">def</span> <span class="nf">format_14</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">locale</span><span class="p">):</span>
+ <span class="c1"># precision: second.</span>
+ <span class="k">return</span> <span class="n">format_datetime</span><span class="p">(</span><span class="n">isoparse</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="nb">format</span><span class="o">=</span><span class="s1">&#39;full&#39;</span><span class="p">,</span> <span class="n">locale</span><span class="o">=</span><span class="n">locale</span><span class="p">)</span>
+
+ <span class="n">DATE_FORMAT</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;0&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">1000000000</span><span class="p">),</span>
+ <span class="s1">&#39;1&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">100000000</span><span class="p">),</span>
+ <span class="s1">&#39;2&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">10000000</span><span class="p">),</span>
+ <span class="s1">&#39;3&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">1000000</span><span class="p">),</span>
+ <span class="s1">&#39;4&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">100000</span><span class="p">),</span>
+ <span class="s1">&#39;5&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">10000</span><span class="p">),</span>
+ <span class="s1">&#39;6&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">1000</span><span class="p">),</span>
+ <span class="s1">&#39;7&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span>
+ <span class="s1">&#39;8&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_8&#39;</span><span class="p">,</span> <span class="mi">10</span><span class="p">),</span>
+ <span class="s1">&#39;9&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_9&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="c1"># year</span>
+ <span class="s1">&#39;10&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_10&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="c1"># month</span>
+ <span class="s1">&#39;11&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_11&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="c1"># day</span>
+ <span class="s1">&#39;12&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_13&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="c1"># hour (not supported by babel, display minute)</span>
+ <span class="s1">&#39;13&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_13&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="c1"># minute</span>
+ <span class="s1">&#39;14&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;format_14&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">),</span> <span class="c1"># second</span>
+ <span class="p">}</span>
+
+ <span class="k">def</span> <span class="nf">get_str</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">result</span><span class="p">,</span> <span class="n">language</span><span class="p">):</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">value</span> <span class="o">==</span> <span class="s1">&#39;&#39;</span> <span class="ow">or</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="kc">None</span>
+ <span class="n">precision</span> <span class="o">=</span> <span class="n">result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s1">&#39;timePrecision&#39;</span><span class="p">)</span>
+ <span class="n">date_format</span> <span class="o">=</span> <span class="n">WDDateAttribute</span><span class="o">.</span><span class="n">DATE_FORMAT</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">precision</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">date_format</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">format_method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">date_format</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
+ <span class="n">precision</span> <span class="o">=</span> <span class="n">date_format</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">precision</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">:</span>
+ <span class="n">t</span> <span class="o">=</span> <span class="n">value</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">value</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">):</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="s1">&#39;-&#39;</span> <span class="o">+</span> <span class="n">t</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="n">t</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="k">return</span> <span class="n">format_method</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> <span class="c1"># pylint: disable=broad-except</span>
+ <span class="k">return</span> <span class="n">value</span>
+ <span class="k">return</span> <span class="n">value</span>
+
+
+<span class="k">def</span> <span class="nf">debug_explain_wikidata_query</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="s1">&#39;GET&#39;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">method</span> <span class="o">==</span> <span class="s1">&#39;GET&#39;</span><span class="p">:</span>
+ <span class="n">http_response</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">SPARQL_EXPLAIN_URL</span> <span class="o">+</span> <span class="s1">&#39;&amp;&#39;</span> <span class="o">+</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">}),</span> <span class="n">headers</span><span class="o">=</span><span class="n">get_headers</span><span class="p">())</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="n">http_response</span> <span class="o">=</span> <span class="n">post</span><span class="p">(</span><span class="n">SPARQL_EXPLAIN_URL</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">},</span> <span class="n">headers</span><span class="o">=</span><span class="n">get_headers</span><span class="p">())</span>
+ <span class="n">http_response</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
+ <span class="k">return</span> <span class="n">http_response</span><span class="o">.</span><span class="n">content</span>
+
+
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span> <span class="c1"># pylint: disable=unused-argument</span>
+ <span class="c1"># WIKIDATA_PROPERTIES : add unit symbols</span>
+ <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">WIKIDATA_UNITS</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="n">WIKIDATA_PROPERTIES</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span><span class="p">[</span><span class="s1">&#39;symbol&#39;</span><span class="p">]</span>
+
+ <span class="c1"># WIKIDATA_PROPERTIES : add property labels</span>
+ <span class="n">wikidata_property_names</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">for</span> <span class="n">attribute</span> <span class="ow">in</span> <span class="n">get_attributes</span><span class="p">(</span><span class="s1">&#39;en&#39;</span><span class="p">):</span>
+ <span class="k">if</span> <span class="nb">type</span><span class="p">(</span><span class="n">attribute</span><span class="p">)</span> <span class="ow">in</span> <span class="p">(</span><span class="n">WDAttribute</span><span class="p">,</span> <span class="n">WDAmountAttribute</span><span class="p">,</span> <span class="n">WDURLAttribute</span><span class="p">,</span> <span class="n">WDDateAttribute</span><span class="p">,</span> <span class="n">WDLabelAttribute</span><span class="p">):</span>
+ <span class="k">if</span> <span class="n">attribute</span><span class="o">.</span><span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">WIKIDATA_PROPERTIES</span><span class="p">:</span>
+ <span class="n">wikidata_property_names</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;wd:&quot;</span> <span class="o">+</span> <span class="n">attribute</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">QUERY_PROPERTY_NAMES</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;%ATTRIBUTES%&#39;</span><span class="p">,</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">wikidata_property_names</span><span class="p">))</span>
+ <span class="n">jsonresponse</span> <span class="o">=</span> <span class="n">send_wikidata_query</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">jsonresponse</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;results&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;bindings&#39;</span><span class="p">,</span> <span class="p">{}):</span>
+ <span class="n">name</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">][</span><span class="s1">&#39;value&#39;</span><span class="p">]</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">][</span><span class="s1">&#39;xml:lang&#39;</span><span class="p">]</span>
+ <span class="n">entity_id</span> <span class="o">=</span> <span class="n">result</span><span class="p">[</span><span class="s1">&#39;item&#39;</span><span class="p">][</span><span class="s1">&#39;value&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;http://www.wikidata.org/entity/&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">WIKIDATA_PROPERTIES</span><span class="p">[(</span><span class="n">entity_id</span><span class="p">,</span> <span class="n">lang</span><span class="p">)]</span> <span class="o">=</span> <span class="n">name</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/wikipedia.html#searx.engines.wikidata.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Uses languages evaluated from :py:obj:`wikipedia.fetch_wikimedia_traits</span>
+<span class="sd"> &lt;searx.engines.wikipedia.fetch_wikimedia_traits&gt;` and removes</span>
+
+<span class="sd"> - ``traits.custom[&#39;wiki_netloc&#39;]``: wikidata does not have net-locations for</span>
+<span class="sd"> the languages and the list of all</span>
+
+<span class="sd"> - ``traits.custom[&#39;WIKIPEDIA_LANGUAGES&#39;]``: not used in the wikipedia engine</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+
+ <span class="n">fetch_wikimedia_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">)</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;WIKIPEDIA_LANGUAGES&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/wikipedia.html b/_modules/searx/engines/wikipedia.html
new file mode 100644
index 000000000..790db54e9
--- /dev/null
+++ b/_modules/searx/engines/wikipedia.html
@@ -0,0 +1,443 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.wikipedia &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.wikipedia</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.wikipedia</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;This module implements the Wikipedia engine. Some of this implementations</span>
+<span class="sd">are shared by other engines:</span>
+
+<span class="sd">- :ref:`wikidata engine`</span>
+
+<span class="sd">The list of supported languages is :py:obj:`fetched &lt;fetch_wikimedia_traits&gt;` from</span>
+<span class="sd">the article linked by :py:obj:`list_of_wikipedias`.</span>
+
+<span class="sd">Unlike traditional search engines, wikipedia does not support one Wikipedia for</span>
+<span class="sd">all languages, but there is one Wikipedia for each supported language. Some of</span>
+<span class="sd">these Wikipedias have a LanguageConverter_ enabled</span>
+<span class="sd">(:py:obj:`rest_v1_summary_url`).</span>
+
+<span class="sd">A LanguageConverter_ (LC) is a system based on language variants that</span>
+<span class="sd">automatically converts the content of a page into a different variant. A variant</span>
+<span class="sd">is mostly the same language in a different script.</span>
+
+<span class="sd">- `Wikipedias in multiple writing systems`_</span>
+<span class="sd">- `Automatic conversion between traditional and simplified Chinese characters`_</span>
+
+<span class="sd">PR-2554_:</span>
+<span class="sd"> The Wikipedia link returned by the API is still the same in all cases</span>
+<span class="sd"> (`https://zh.wikipedia.org/wiki/出租車`_) but if your browser&#39;s</span>
+<span class="sd"> ``Accept-Language`` is set to any of ``zh``, ``zh-CN``, ``zh-TW``, ``zh-HK``</span>
+<span class="sd"> or .. Wikipedia&#39;s LC automatically returns the desired script in their</span>
+<span class="sd"> web-page.</span>
+
+<span class="sd"> - You can test the API here: https://reqbin.com/gesg2kvx</span>
+
+<span class="sd">.. _https://zh.wikipedia.org/wiki/出租車:</span>
+<span class="sd"> https://zh.wikipedia.org/wiki/%E5%87%BA%E7%A7%9F%E8%BB%8A</span>
+
+<span class="sd">To support Wikipedia&#39;s LanguageConverter_, a SearXNG request to Wikipedia uses</span>
+<span class="sd">:py:obj:`get_wiki_params` and :py:obj:`wiki_lc_locale_variants&#39; in the</span>
+<span class="sd">:py:obj:`fetch_wikimedia_traits` function.</span>
+
+<span class="sd">To test in SearXNG, query for ``!wp 出租車`` with each of the available Chinese</span>
+<span class="sd">options:</span>
+
+<span class="sd">- ``!wp 出租車 :zh`` should show 出租車</span>
+<span class="sd">- ``!wp 出租車 :zh-CN`` should show 出租车</span>
+<span class="sd">- ``!wp 出租車 :zh-TW`` should show 計程車</span>
+<span class="sd">- ``!wp 出租車 :zh-HK`` should show 的士</span>
+<span class="sd">- ``!wp 出租車 :zh-SG`` should show 德士</span>
+
+<span class="sd">.. _LanguageConverter:</span>
+<span class="sd"> https://www.mediawiki.org/wiki/Writing_systems#LanguageConverter</span>
+<span class="sd">.. _Wikipedias in multiple writing systems:</span>
+<span class="sd"> https://meta.wikimedia.org/wiki/Wikipedias_in_multiple_writing_systems</span>
+<span class="sd">.. _Automatic conversion between traditional and simplified Chinese characters:</span>
+<span class="sd"> https://en.wikipedia.org/wiki/Chinese_Wikipedia#Automatic_conversion_between_traditional_and_simplified_Chinese_characters</span>
+<span class="sd">.. _PR-2554: https://github.com/searx/searx/pull/2554</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">import</span> <span class="nn">urllib.parse</span>
+<span class="kn">import</span> <span class="nn">babel</span>
+
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">utils</span>
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">network</span> <span class="k">as</span> <span class="n">_network</span>
+<span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">locales</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://www.wikipedia.org/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s1">&#39;Q52&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://en.wikipedia.org/api/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;JSON&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">display_type</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;infobox&quot;</span><span class="p">]</span>
+<span class="sd">&quot;&quot;&quot;A list of display types composed from ``infobox`` and ``list``. The latter</span>
+<span class="sd">one will add a hit to the result list. The first one will show a hit in the</span>
+<span class="sd">info box. Both values can be set, or one of the two can be set.&quot;&quot;&quot;</span>
+
+<span class="n">send_accept_language_header</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="sd">&quot;&quot;&quot;The HTTP ``Accept-Language`` header is needed for wikis where</span>
+<span class="sd">LanguageConverter_ is enabled.&quot;&quot;&quot;</span>
+
+<span class="n">list_of_wikipedias</span> <span class="o">=</span> <span class="s1">&#39;https://meta.wikimedia.org/wiki/List_of_Wikipedias&#39;</span>
+<span class="sd">&quot;&quot;&quot;`List of all wikipedias &lt;https://meta.wikimedia.org/wiki/List_of_Wikipedias&gt;`_</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">wikipedia_article_depth</span> <span class="o">=</span> <span class="s1">&#39;https://meta.wikimedia.org/wiki/Wikipedia_article_depth&#39;</span>
+<span class="sd">&quot;&quot;&quot;The *editing depth* of Wikipedia is one of several possible rough indicators</span>
+<span class="sd">of the encyclopedia&#39;s collaborative quality, showing how frequently its articles</span>
+<span class="sd">are updated. The measurement of depth was introduced after some limitations of</span>
+<span class="sd">the classic measurement of article count were realized.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">rest_v1_summary_url</span> <span class="o">=</span> <span class="s1">&#39;https://</span><span class="si">{wiki_netloc}</span><span class="s1">/api/rest_v1/page/summary/</span><span class="si">{title}</span><span class="s1">&#39;</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">`wikipedia rest_v1 summary API`_:</span>
+<span class="sd"> The summary response includes an extract of the first paragraph of the page in</span>
+<span class="sd"> plain text and HTML as well as the type of page. This is useful for page</span>
+<span class="sd"> previews (fka. Hovercards, aka. Popups) on the web and link previews in the</span>
+<span class="sd"> apps.</span>
+
+<span class="sd">HTTP ``Accept-Language`` header (:py:obj:`send_accept_language_header`):</span>
+<span class="sd"> The desired language variant code for wikis where LanguageConverter_ is</span>
+<span class="sd"> enabled.</span>
+
+<span class="sd">.. _wikipedia rest_v1 summary API:</span>
+<span class="sd"> https://en.wikipedia.org/api/rest_v1/#/Page%20content/get_page_summary__title_</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">wiki_lc_locale_variants</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;zh&quot;</span><span class="p">:</span> <span class="p">(</span>
+ <span class="s2">&quot;zh-CN&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh-HK&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh-MO&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh-MY&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh-SG&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh-TW&quot;</span><span class="p">,</span>
+ <span class="p">),</span>
+ <span class="s2">&quot;zh-classical&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;zh-classical&quot;</span><span class="p">,),</span>
+<span class="p">}</span>
+<span class="sd">&quot;&quot;&quot;Mapping rule of the LanguageConverter_ to map a language and its variants to</span>
+<span class="sd">a Locale (used in the HTTP ``Accept-Language`` header). For example see `LC</span>
+<span class="sd">Chinese`_.</span>
+
+<span class="sd">.. _LC Chinese:</span>
+<span class="sd"> https://meta.wikimedia.org/wiki/Wikipedias_in_multiple_writing_systems#Chinese</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">wikipedia_script_variants</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;zh&quot;</span><span class="p">:</span> <span class="p">(</span>
+ <span class="s2">&quot;zh_Hant&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;zh_Hans&quot;</span><span class="p">,</span>
+ <span class="p">)</span>
+<span class="p">}</span>
+
+
+<div class="viewcode-block" id="get_wiki_params">
+<a class="viewcode-back" href="../../../dev/engines/online/wikipedia.html#searx.engines.wikipedia.get_wiki_params">[docs]</a>
+<span class="k">def</span> <span class="nf">get_wiki_params</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">eng_traits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Returns the Wikipedia language tag and the netloc that fits to the</span>
+<span class="sd"> ``sxng_locale``. To support LanguageConverter_ this function rates a locale</span>
+<span class="sd"> (region) higher than a language (compare :py:obj:`wiki_lc_locale_variants`).</span>
+
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">get_region</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">sxng_locale</span><span class="p">,</span> <span class="s1">&#39;en&#39;</span><span class="p">))</span>
+ <span class="n">wiki_netloc</span> <span class="o">=</span> <span class="n">eng_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">,</span> <span class="s1">&#39;en.wikipedia.org&#39;</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="n">wiki_netloc</span></div>
+
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/wikipedia.html#searx.engines.wikipedia.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Assemble a request (`wikipedia rest_v1 summary API`_).&quot;&quot;&quot;</span>
+ <span class="k">if</span> <span class="n">query</span><span class="o">.</span><span class="n">islower</span><span class="p">():</span>
+ <span class="n">query</span> <span class="o">=</span> <span class="n">query</span><span class="o">.</span><span class="n">title</span><span class="p">()</span>
+
+ <span class="n">_eng_tag</span><span class="p">,</span> <span class="n">wiki_netloc</span> <span class="o">=</span> <span class="n">get_wiki_params</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;searxng_locale&#39;</span><span class="p">],</span> <span class="n">traits</span><span class="p">)</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">quote</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">rest_v1_summary_url</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">wiki_netloc</span><span class="o">=</span><span class="n">wiki_netloc</span><span class="p">,</span> <span class="n">title</span><span class="o">=</span><span class="n">title</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;raise_for_httperror&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;soft_max_redirects&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">2</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<span class="c1"># get response from search-request</span>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">404</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+ <span class="k">if</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">400</span><span class="p">:</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">api_result</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span> <span class="c1"># pylint: disable=broad-except</span>
+ <span class="k">pass</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">if</span> <span class="p">(</span>
+ <span class="n">api_result</span><span class="p">[</span><span class="s1">&#39;type&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;https://mediawiki.org/wiki/HyperSwitch/errors/bad_request&#39;</span>
+ <span class="ow">and</span> <span class="n">api_result</span><span class="p">[</span><span class="s1">&#39;detail&#39;</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;title-invalid-characters&#39;</span>
+ <span class="p">):</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="n">_network</span><span class="o">.</span><span class="n">raise_for_httperror</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="n">api_result</span> <span class="o">=</span> <span class="n">resp</span><span class="o">.</span><span class="n">json</span><span class="p">()</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">html_to_text</span><span class="p">(</span><span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;titles&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;display&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;title&#39;</span><span class="p">))</span>
+ <span class="n">wikipedia_link</span> <span class="o">=</span> <span class="n">api_result</span><span class="p">[</span><span class="s1">&#39;content_urls&#39;</span><span class="p">][</span><span class="s1">&#39;desktop&#39;</span><span class="p">][</span><span class="s1">&#39;page&#39;</span><span class="p">]</span>
+
+ <span class="k">if</span> <span class="s2">&quot;list&quot;</span> <span class="ow">in</span> <span class="n">display_type</span> <span class="ow">or</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;type&#39;</span><span class="p">)</span> <span class="o">!=</span> <span class="s1">&#39;standard&#39;</span><span class="p">:</span>
+ <span class="c1"># show item in the result list if &#39;list&#39; is in the display options or it</span>
+ <span class="c1"># is a item that can&#39;t be displayed in a infobox.</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">wikipedia_link</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)})</span>
+
+ <span class="k">if</span> <span class="s2">&quot;infobox&quot;</span> <span class="ow">in</span> <span class="n">display_type</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;type&#39;</span><span class="p">)</span> <span class="o">==</span> <span class="s1">&#39;standard&#39;</span><span class="p">:</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;infobox&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;id&#39;</span><span class="p">:</span> <span class="n">wikipedia_link</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;extract&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;img_src&#39;</span><span class="p">:</span> <span class="n">api_result</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">,</span> <span class="p">{})</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;source&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;urls&#39;</span><span class="p">:</span> <span class="p">[{</span><span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="s1">&#39;Wikipedia&#39;</span><span class="p">,</span> <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">wikipedia_link</span><span class="p">}],</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="c1"># Nonstandard language codes</span>
+<span class="c1">#</span>
+<span class="c1"># These Wikipedias use language codes that do not conform to the ISO 639</span>
+<span class="c1"># standard (which is how wiki subdomains are chosen nowadays).</span>
+
+<span class="n">lang_map</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">LOCALE_BEST_MATCH</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
+<span class="n">lang_map</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;be-tarask&#39;</span><span class="p">:</span> <span class="s1">&#39;bel&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ak&#39;</span><span class="p">:</span> <span class="s1">&#39;aka&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;als&#39;</span><span class="p">:</span> <span class="s1">&#39;gsw&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;bat-smg&#39;</span><span class="p">:</span> <span class="s1">&#39;sgs&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;cbk-zam&#39;</span><span class="p">:</span> <span class="s1">&#39;cbk&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fiu-vro&#39;</span><span class="p">:</span> <span class="s1">&#39;vro&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;map-bms&#39;</span><span class="p">:</span> <span class="s1">&#39;map&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;no&#39;</span><span class="p">:</span> <span class="s1">&#39;nb-NO&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;nrm&#39;</span><span class="p">:</span> <span class="s1">&#39;nrf&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;roa-rup&#39;</span><span class="p">:</span> <span class="s1">&#39;rup&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;nds-nl&#39;</span><span class="p">:</span> <span class="s1">&#39;nds&#39;</span><span class="p">,</span>
+ <span class="c1">#&#39;simple: – invented code used for the Simple English Wikipedia (not the official IETF code en-simple)</span>
+ <span class="s1">&#39;zh-min-nan&#39;</span><span class="p">:</span> <span class="s1">&#39;nan&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;zh-yue&#39;</span><span class="p">:</span> <span class="s1">&#39;yue&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;an&#39;</span><span class="p">:</span> <span class="s1">&#39;arg&#39;</span><span class="p">,</span>
+ <span class="p">}</span>
+<span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+ <span class="n">fetch_wikimedia_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">)</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;WIKIPEDIA_LANGUAGES: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="nb">len</span><span class="p">(</span><span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;WIKIPEDIA_LANGUAGES&#39;</span><span class="p">]))</span>
+
+
+<div class="viewcode-block" id="fetch_wikimedia_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/wikipedia.html#searx.engines.wikipedia.fetch_wikimedia_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_wikimedia_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages from Wikipedia. Not all languages from the</span>
+<span class="sd"> :py:obj:`list_of_wikipedias` are supported by SearXNG locales, only those</span>
+<span class="sd"> known from :py:obj:`searx.locales.LOCALE_NAMES` or those with a minimal</span>
+<span class="sd"> :py:obj:`editing depth &lt;wikipedia_article_depth&gt;`.</span>
+
+<span class="sd"> The location of the Wikipedia address of a language is mapped in a</span>
+<span class="sd"> :py:obj:`custom field &lt;searx.enginelib.traits.EngineTraits.custom&gt;`</span>
+<span class="sd"> (``wiki_netloc``). Here is a reduced example:</span>
+
+<span class="sd"> .. code:: python</span>
+
+<span class="sd"> traits.custom[&#39;wiki_netloc&#39;] = {</span>
+<span class="sd"> &quot;en&quot;: &quot;en.wikipedia.org&quot;,</span>
+<span class="sd"> ..</span>
+<span class="sd"> &quot;gsw&quot;: &quot;als.wikipedia.org&quot;,</span>
+<span class="sd"> ..</span>
+<span class="sd"> &quot;zh&quot;: &quot;zh.wikipedia.org&quot;,</span>
+<span class="sd"> &quot;zh-classical&quot;: &quot;zh-classical.wikipedia.org&quot;</span>
+<span class="sd"> }</span>
+<span class="sd"> &quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=too-many-branches</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;WIKIPEDIA_LANGUAGES&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="c1"># insert alias to map from a script or region to a wikipedia variant</span>
+
+ <span class="k">for</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="n">sxng_tag_list</span> <span class="ow">in</span> <span class="n">wikipedia_script_variants</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="k">for</span> <span class="n">sxng_tag</span> <span class="ow">in</span> <span class="n">sxng_tag_list</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+ <span class="k">for</span> <span class="n">eng_tag</span><span class="p">,</span> <span class="n">sxng_tag_list</span> <span class="ow">in</span> <span class="n">wiki_lc_locale_variants</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
+ <span class="k">for</span> <span class="n">sxng_tag</span> <span class="ow">in</span> <span class="n">sxng_tag_list</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">regions</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">_network</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">list_of_wikipedias</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from Wikipedia is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//table[contains(@class,&quot;sortable&quot;)]//tbody/tr&#39;</span><span class="p">):</span>
+
+ <span class="n">cols</span> <span class="o">=</span> <span class="n">row</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;./td&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">cols</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">cols</span> <span class="o">=</span> <span class="p">[</span><span class="n">c</span><span class="o">.</span><span class="n">text_content</span><span class="p">()</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="n">cols</span><span class="p">]</span>
+
+ <span class="n">depth</span> <span class="o">=</span> <span class="nb">float</span><span class="p">(</span><span class="n">cols</span><span class="p">[</span><span class="mi">11</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">,</span> <span class="s1">&#39;0&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
+ <span class="n">articles</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">cols</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s1">&#39;,&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
+
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">cols</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span>
+ <span class="n">wiki_url</span> <span class="o">=</span> <span class="n">row</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;./td[4]/a/@href&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">wiki_url</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">parse</span><span class="o">.</span><span class="n">urlparse</span><span class="p">(</span><span class="n">wiki_url</span><span class="p">)</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">locales</span><span class="o">.</span><span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">lang_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">),</span> <span class="n">sep</span><span class="o">=</span><span class="s1">&#39;-&#39;</span><span class="p">))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="c1"># print(&quot;ERROR: %s [%s] is unknown by babel&quot; % (cols[0], eng_tag))</span>
+ <span class="k">continue</span>
+ <span class="k">finally</span><span class="p">:</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;WIKIPEDIA_LANGUAGES&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">sxng_tag</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">locales</span><span class="o">.</span><span class="n">LOCALE_NAMES</span><span class="p">:</span>
+
+ <span class="k">if</span> <span class="n">articles</span> <span class="o">&lt;</span> <span class="mi">10000</span><span class="p">:</span>
+ <span class="c1"># exclude languages with too few articles</span>
+ <span class="k">continue</span>
+
+ <span class="k">if</span> <span class="nb">int</span><span class="p">(</span><span class="n">depth</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">20</span><span class="p">:</span>
+ <span class="c1"># Rough indicator of a Wikipedia’s quality, showing how</span>
+ <span class="c1"># frequently its articles are updated.</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;wiki_netloc&#39;</span><span class="p">][</span><span class="n">eng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">wiki_url</span><span class="o">.</span><span class="n">netloc</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s1">&#39;WIKIPEDIA_LANGUAGES&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/xpath.html b/_modules/searx/engines/xpath.html
new file mode 100644
index 000000000..cec0b4d47
--- /dev/null
+++ b/_modules/searx/engines/xpath.html
@@ -0,0 +1,446 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.xpath &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.xpath</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.xpath</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;The XPath engine is a *generic* engine with which it is possible to configure</span>
+<span class="sd">engines in the settings.</span>
+
+<span class="sd">.. _XPath selector: https://quickref.me/xpath.html#xpath-selectors</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">Request:</span>
+
+<span class="sd">- :py:obj:`search_url`</span>
+<span class="sd">- :py:obj:`lang_all`</span>
+<span class="sd">- :py:obj:`soft_max_redirects`</span>
+<span class="sd">- :py:obj:`method`</span>
+<span class="sd">- :py:obj:`request_body`</span>
+<span class="sd">- :py:obj:`cookies`</span>
+<span class="sd">- :py:obj:`headers`</span>
+
+<span class="sd">Paging:</span>
+
+<span class="sd">- :py:obj:`paging`</span>
+<span class="sd">- :py:obj:`page_size`</span>
+<span class="sd">- :py:obj:`first_page_num`</span>
+
+<span class="sd">Time Range:</span>
+
+<span class="sd">- :py:obj:`time_range_support`</span>
+<span class="sd">- :py:obj:`time_range_url`</span>
+<span class="sd">- :py:obj:`time_range_map`</span>
+
+<span class="sd">Safe-Search:</span>
+
+<span class="sd">- :py:obj:`safe_search_support`</span>
+<span class="sd">- :py:obj:`safe_search_map`</span>
+
+<span class="sd">Response:</span>
+
+<span class="sd">- :py:obj:`no_result_for_http_status`</span>
+
+<span class="sd">`XPath selector`_:</span>
+
+<span class="sd">- :py:obj:`results_xpath`</span>
+<span class="sd">- :py:obj:`url_xpath`</span>
+<span class="sd">- :py:obj:`title_xpath`</span>
+<span class="sd">- :py:obj:`content_xpath`</span>
+<span class="sd">- :py:obj:`thumbnail_xpath`</span>
+<span class="sd">- :py:obj:`suggestion_xpath`</span>
+
+
+<span class="sd">Example</span>
+<span class="sd">=======</span>
+
+<span class="sd">Here is a simple example of a XPath engine configured in the :ref:`settings</span>
+<span class="sd">engine` section, further read :ref:`engines-dev`.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name : bitbucket</span>
+<span class="sd"> engine : xpath</span>
+<span class="sd"> paging : True</span>
+<span class="sd"> search_url : https://bitbucket.org/repo/all/{pageno}?name={query}</span>
+<span class="sd"> url_xpath : //article[@class=&quot;repo-summary&quot;]//a[@class=&quot;repo-link&quot;]/@href</span>
+<span class="sd"> title_xpath : //article[@class=&quot;repo-summary&quot;]//a[@class=&quot;repo-link&quot;]</span>
+<span class="sd"> content_xpath : //article[@class=&quot;repo-summary&quot;]/p</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">urlencode</span>
+
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">extract_url</span><span class="p">,</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">eval_xpath_list</span>
+<span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">raise_for_httperror</span>
+
+<span class="n">search_url</span> <span class="o">=</span> <span class="kc">None</span>
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="sd">Search URL of the engine. Example::</span>
+
+<span class="sd"> https://example.org/?search={query}&amp;page={pageno}{time_range}{safe_search}</span>
+
+<span class="sd">Replacements are:</span>
+
+<span class="sd">``{query}``:</span>
+<span class="sd"> Search terms from user.</span>
+
+<span class="sd">``{pageno}``:</span>
+<span class="sd"> Page number if engine supports paging :py:obj:`paging`</span>
+
+<span class="sd">``{lang}``:</span>
+<span class="sd"> ISO 639-1 language code (en, de, fr ..)</span>
+
+<span class="sd">``{time_range}``:</span>
+<span class="sd"> :py:obj:`URL parameter &lt;time_range_url&gt;` if engine :py:obj:`supports time</span>
+<span class="sd"> range &lt;time_range_support&gt;`. The value for the parameter is taken from</span>
+<span class="sd"> :py:obj:`time_range_map`.</span>
+
+<span class="sd">``{safe_search}``:</span>
+<span class="sd"> Safe-search :py:obj:`URL parameter &lt;safe_search_map&gt;` if engine</span>
+<span class="sd"> :py:obj:`supports safe-search &lt;safe_search_support&gt;`. The ``{safe_search}``</span>
+<span class="sd"> replacement is taken from the :py:obj:`safes_search_map`. Filter results::</span>
+
+<span class="sd"> 0: none, 1: moderate, 2:strict</span>
+
+<span class="sd"> If not supported, the URL parameter is an empty string.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">lang_all</span> <span class="o">=</span> <span class="s1">&#39;en&#39;</span>
+<span class="sd">&#39;&#39;&#39;Replacement ``{lang}`` in :py:obj:`search_url` if language ``all`` is</span>
+<span class="sd">selected.</span>
+<span class="sd">&#39;&#39;&#39;</span>
+
+<span class="n">no_result_for_http_status</span> <span class="o">=</span> <span class="p">[]</span>
+<span class="sd">&#39;&#39;&#39;Return empty result for these HTTP status codes instead of throwing an error.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> no_result_for_http_status: []</span>
+<span class="sd">&#39;&#39;&#39;</span>
+
+<span class="n">soft_max_redirects</span> <span class="o">=</span> <span class="mi">0</span>
+<span class="sd">&#39;&#39;&#39;Maximum redirects, soft limit. Record an error but don&#39;t stop the engine&#39;&#39;&#39;</span>
+
+<span class="n">results_xpath</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ for the list of result items&#39;&#39;&#39;</span>
+
+<span class="n">url_xpath</span> <span class="o">=</span> <span class="kc">None</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ of result&#39;s ``url``.&#39;&#39;&#39;</span>
+
+<span class="n">content_xpath</span> <span class="o">=</span> <span class="kc">None</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ of result&#39;s ``content``.&#39;&#39;&#39;</span>
+
+<span class="n">title_xpath</span> <span class="o">=</span> <span class="kc">None</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ of result&#39;s ``title``.&#39;&#39;&#39;</span>
+
+<span class="n">thumbnail_xpath</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ of result&#39;s ``thumbnail``.&#39;&#39;&#39;</span>
+
+<span class="n">suggestion_xpath</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="sd">&#39;&#39;&#39;`XPath selector`_ of result&#39;s ``suggestion``.&#39;&#39;&#39;</span>
+
+<span class="n">cached_xpath</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="n">cached_url</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+
+<span class="n">cookies</span> <span class="o">=</span> <span class="p">{}</span>
+<span class="sd">&#39;&#39;&#39;Some engines might offer different result based on cookies.</span>
+<span class="sd">Possible use-case: To set safesearch cookie.&#39;&#39;&#39;</span>
+
+<span class="n">headers</span> <span class="o">=</span> <span class="p">{}</span>
+<span class="sd">&#39;&#39;&#39;Some engines might offer different result based headers. Possible use-case:</span>
+<span class="sd">To set header to moderate.&#39;&#39;&#39;</span>
+
+<span class="n">method</span> <span class="o">=</span> <span class="s1">&#39;GET&#39;</span>
+<span class="sd">&#39;&#39;&#39;Some engines might require to do POST requests for search.&#39;&#39;&#39;</span>
+
+<span class="n">request_body</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+<span class="sd">&#39;&#39;&#39;The body of the request. This can only be used if different :py:obj:`method`</span>
+<span class="sd">is set, e.g. ``POST``. For formatting see the documentation of :py:obj:`search_url`::</span>
+
+<span class="sd"> search={query}&amp;page={pageno}{time_range}{safe_search}</span>
+<span class="sd">&#39;&#39;&#39;</span>
+
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&#39;&#39;&#39;Engine supports paging [True or False].&#39;&#39;&#39;</span>
+
+<span class="n">page_size</span> <span class="o">=</span> <span class="mi">1</span>
+<span class="sd">&#39;&#39;&#39;Number of results on each page. Only needed if the site requires not a page</span>
+<span class="sd">number, but an offset.&#39;&#39;&#39;</span>
+
+<span class="n">first_page_num</span> <span class="o">=</span> <span class="mi">1</span>
+<span class="sd">&#39;&#39;&#39;Number of the first page (usually 0 or 1).&#39;&#39;&#39;</span>
+
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&#39;&#39;&#39;Engine supports search time range.&#39;&#39;&#39;</span>
+
+<span class="n">time_range_url</span> <span class="o">=</span> <span class="s1">&#39;&amp;hours=</span><span class="si">{time_range_val}</span><span class="s1">&#39;</span>
+<span class="sd">&#39;&#39;&#39;Time range URL parameter in the in :py:obj:`search_url`. If no time range is</span>
+<span class="sd">requested by the user, the URL parameter is an empty string. The</span>
+<span class="sd">``{time_range_val}`` replacement is taken from the :py:obj:`time_range_map`.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> time_range_url : &#39;&amp;days={time_range_val}&#39;</span>
+<span class="sd">&#39;&#39;&#39;</span>
+
+<span class="n">time_range_map</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="mi">24</span><span class="p">,</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">7</span><span class="p">,</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">30</span><span class="p">,</span>
+ <span class="s1">&#39;year&#39;</span><span class="p">:</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">365</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="sd">&#39;&#39;&#39;Maps time range value from user to ``{time_range_val}`` in</span>
+<span class="sd">:py:obj:`time_range_url`.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> time_range_map:</span>
+<span class="sd"> day: 1</span>
+<span class="sd"> week: 7</span>
+<span class="sd"> month: 30</span>
+<span class="sd"> year: 365</span>
+<span class="sd">&#39;&#39;&#39;</span>
+
+<span class="n">safe_search_support</span> <span class="o">=</span> <span class="kc">False</span>
+<span class="sd">&#39;&#39;&#39;Engine supports safe-search.&#39;&#39;&#39;</span>
+
+<span class="n">safe_search_map</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s1">&#39;&amp;filter=none&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">:</span> <span class="s1">&#39;&amp;filter=moderate&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s1">&#39;&amp;filter=strict&#39;</span><span class="p">}</span>
+<span class="sd">&#39;&#39;&#39;Maps safe-search value to ``{safe_search}`` in :py:obj:`search_url`.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> safesearch: true</span>
+<span class="sd"> safes_search_map:</span>
+<span class="sd"> 0: &#39;&amp;filter=none&#39;</span>
+<span class="sd"> 1: &#39;&amp;filter=moderate&#39;</span>
+<span class="sd"> 2: &#39;&amp;filter=strict&#39;</span>
+
+<span class="sd">&#39;&#39;&#39;</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/xpath.html#searx.engines.xpath.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&#39;&#39;&#39;Build request parameters (see :ref:`engine request`).&#39;&#39;&#39;</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">lang_all</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span> <span class="o">!=</span> <span class="s1">&#39;all&#39;</span><span class="p">:</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">][:</span><span class="mi">2</span><span class="p">]</span>
+
+ <span class="n">time_range</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="k">if</span> <span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;time_range&#39;</span><span class="p">):</span>
+ <span class="n">time_range_val</span> <span class="o">=</span> <span class="n">time_range_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;time_range&#39;</span><span class="p">))</span>
+ <span class="n">time_range</span> <span class="o">=</span> <span class="n">time_range_url</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">time_range_val</span><span class="o">=</span><span class="n">time_range_val</span><span class="p">)</span>
+
+ <span class="n">safe_search</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span>
+ <span class="k">if</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]:</span>
+ <span class="n">safe_search</span> <span class="o">=</span> <span class="n">safe_search_map</span><span class="p">[</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;safesearch&#39;</span><span class="p">]]</span>
+
+ <span class="n">fargs</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;query&#39;</span><span class="p">:</span> <span class="n">urlencode</span><span class="p">({</span><span class="s1">&#39;q&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">})[</span><span class="mi">2</span><span class="p">:],</span>
+ <span class="s1">&#39;lang&#39;</span><span class="p">:</span> <span class="n">lang</span><span class="p">,</span>
+ <span class="s1">&#39;pageno&#39;</span><span class="p">:</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="n">page_size</span> <span class="o">+</span> <span class="n">first_page_num</span><span class="p">,</span>
+ <span class="s1">&#39;time_range&#39;</span><span class="p">:</span> <span class="n">time_range</span><span class="p">,</span>
+ <span class="s1">&#39;safe_search&#39;</span><span class="p">:</span> <span class="n">safe_search</span><span class="p">,</span>
+ <span class="p">}</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;cookies&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">cookies</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;headers&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">headers</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">fargs</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;method&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">method</span>
+
+ <span class="k">if</span> <span class="n">request_body</span><span class="p">:</span>
+ <span class="c1"># don&#39;t url-encode the query if it&#39;s in the request body</span>
+ <span class="n">fargs</span><span class="p">[</span><span class="s1">&#39;query&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">query</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;data&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">request_body</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="o">**</span><span class="n">fargs</span><span class="p">)</span>
+
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;soft_max_redirects&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">soft_max_redirects</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;raise_for_httperror&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/xpath.html#searx.engines.xpath.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span> <span class="c1"># pylint: disable=too-many-branches</span>
+<span class="w"> </span><span class="sd">&#39;&#39;&#39;Scrap *results* from the response (see :ref:`engine results`).&#39;&#39;&#39;</span>
+ <span class="k">if</span> <span class="n">no_result_for_http_status</span> <span class="ow">and</span> <span class="n">resp</span><span class="o">.</span><span class="n">status_code</span> <span class="ow">in</span> <span class="n">no_result_for_http_status</span><span class="p">:</span>
+ <span class="k">return</span> <span class="p">[]</span>
+
+ <span class="n">raise_for_httperror</span><span class="p">(</span><span class="n">resp</span><span class="p">)</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">results</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">is_onion</span> <span class="o">=</span> <span class="s1">&#39;onions&#39;</span> <span class="ow">in</span> <span class="n">categories</span>
+
+ <span class="k">if</span> <span class="n">results_xpath</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">results_xpath</span><span class="p">):</span>
+
+ <span class="n">url</span> <span class="o">=</span> <span class="n">extract_url</span><span class="p">(</span><span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">url_xpath</span><span class="p">,</span> <span class="n">min_len</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span> <span class="n">search_url</span><span class="p">)</span>
+ <span class="n">title</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">title_xpath</span><span class="p">,</span> <span class="n">min_len</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">content_xpath</span><span class="p">))</span>
+ <span class="n">tmp_result</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">}</span>
+
+ <span class="c1"># add thumbnail if available</span>
+ <span class="k">if</span> <span class="n">thumbnail_xpath</span><span class="p">:</span>
+ <span class="n">thumbnail_xpath_result</span> <span class="o">=</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">thumbnail_xpath</span><span class="p">)</span>
+ <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">thumbnail_xpath_result</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="n">tmp_result</span><span class="p">[</span><span class="s1">&#39;thumbnail&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">extract_url</span><span class="p">(</span><span class="n">thumbnail_xpath_result</span><span class="p">,</span> <span class="n">search_url</span><span class="p">)</span>
+
+ <span class="c1"># add alternative cached url if available</span>
+ <span class="k">if</span> <span class="n">cached_xpath</span><span class="p">:</span>
+ <span class="n">tmp_result</span><span class="p">[</span><span class="s1">&#39;cached_url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">cached_url</span> <span class="o">+</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">cached_xpath</span><span class="p">,</span> <span class="n">min_len</span><span class="o">=</span><span class="mi">1</span><span class="p">))</span>
+
+ <span class="k">if</span> <span class="n">is_onion</span><span class="p">:</span>
+ <span class="n">tmp_result</span><span class="p">[</span><span class="s1">&#39;is_onion&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">True</span>
+
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tmp_result</span><span class="p">)</span>
+
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">cached_xpath</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">url</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">content</span><span class="p">,</span> <span class="n">cached</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span>
+ <span class="p">(</span><span class="n">extract_url</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">search_url</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">url_xpath</span><span class="p">)),</span>
+ <span class="nb">map</span><span class="p">(</span><span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">title_xpath</span><span class="p">)),</span>
+ <span class="nb">map</span><span class="p">(</span><span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">content_xpath</span><span class="p">)),</span>
+ <span class="nb">map</span><span class="p">(</span><span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">cached_xpath</span><span class="p">)),</span>
+ <span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span>
+ <span class="s1">&#39;cached_url&#39;</span><span class="p">:</span> <span class="n">cached_url</span> <span class="o">+</span> <span class="n">cached</span><span class="p">,</span>
+ <span class="s1">&#39;is_onion&#39;</span><span class="p">:</span> <span class="n">is_onion</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+ <span class="k">else</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">url</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">content</span> <span class="ow">in</span> <span class="nb">zip</span><span class="p">(</span>
+ <span class="p">(</span><span class="n">extract_url</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">search_url</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">url_xpath</span><span class="p">)),</span>
+ <span class="nb">map</span><span class="p">(</span><span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">title_xpath</span><span class="p">)),</span>
+ <span class="nb">map</span><span class="p">(</span><span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">content_xpath</span><span class="p">)),</span>
+ <span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="n">title</span><span class="p">,</span> <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="n">content</span><span class="p">,</span> <span class="s1">&#39;is_onion&#39;</span><span class="p">:</span> <span class="n">is_onion</span><span class="p">})</span>
+
+ <span class="k">if</span> <span class="n">suggestion_xpath</span><span class="p">:</span>
+ <span class="k">for</span> <span class="n">suggestion</span> <span class="ow">in</span> <span class="n">eval_xpath</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="n">suggestion_xpath</span><span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)})</span>
+
+ <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;found </span><span class="si">%s</span><span class="s2"> results&quot;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">results</span><span class="p">))</span>
+ <span class="k">return</span> <span class="n">results</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/yahoo.html b/_modules/searx/engines/yahoo.html
new file mode 100644
index 000000000..ce3b10d19
--- /dev/null
+++ b/_modules/searx/engines/yahoo.html
@@ -0,0 +1,312 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.yahoo &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.yahoo</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.yahoo</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;Yahoo Search (Web)</span>
+
+<span class="sd">Languages are supported by mapping the language to a domain. If domain is not</span>
+<span class="sd">found in :py:obj:`lang2domain` URL ``&lt;lang&gt;.search.yahoo.com`` is used.</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">unquote</span><span class="p">,</span>
+ <span class="n">urlencode</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="p">(</span>
+ <span class="n">eval_xpath_getindex</span><span class="p">,</span>
+ <span class="n">eval_xpath_list</span><span class="p">,</span>
+ <span class="n">extract_text</span><span class="p">,</span>
+ <span class="n">html_to_text</span><span class="p">,</span>
+<span class="p">)</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+
+<span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s1">&#39;https://search.yahoo.com/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="s1">&#39;https://developer.yahoo.com/api/&#39;</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s1">&#39;HTML&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="c1"># engine dependent config</span>
+<span class="n">categories</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;general&#39;</span><span class="p">,</span> <span class="s1">&#39;web&#39;</span><span class="p">]</span>
+<span class="n">paging</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">time_range_support</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="c1"># send_accept_language_header = True</span>
+
+<span class="n">time_range_dict</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;day&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;1d&#39;</span><span class="p">,</span> <span class="s1">&#39;d&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;week&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;1w&#39;</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">),</span>
+ <span class="s1">&#39;month&#39;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;1m&#39;</span><span class="p">,</span> <span class="s1">&#39;m&#39;</span><span class="p">),</span>
+<span class="p">}</span>
+
+<span class="n">lang2domain</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;zh_chs&#39;</span><span class="p">:</span> <span class="s1">&#39;hk.search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;zh_cht&#39;</span><span class="p">:</span> <span class="s1">&#39;tw.search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;any&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;en&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;bg&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;cs&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;da&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;el&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;et&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;he&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;hr&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ja&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;ko&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sk&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;sl&#39;</span><span class="p">:</span> <span class="s1">&#39;search.yahoo.com&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+<span class="sd">&quot;&quot;&quot;Map language to domain&quot;&quot;&quot;</span>
+
+<span class="n">locale_aliases</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s1">&#39;zh&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hans&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;zh-HK&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hans&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;zh-CN&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hans&#39;</span><span class="p">,</span> <span class="c1"># dead since 2015 / routed to hk.search.yahoo.com</span>
+ <span class="s1">&#39;zh-TW&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hant&#39;</span><span class="p">,</span>
+<span class="p">}</span>
+
+
+<div class="viewcode-block" id="request">
+<a class="viewcode-back" href="../../../dev/engines/online/yahoo.html#searx.engines.yahoo.request">[docs]</a>
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;build request&quot;&quot;&quot;</span>
+
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">locale_aliases</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">],</span> <span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">lang</span><span class="p">:</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="s1">&#39;language&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">&#39;-&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
+ <span class="n">lang</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">lang</span><span class="p">,</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span>
+
+ <span class="n">offset</span> <span class="o">=</span> <span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;pageno&#39;</span><span class="p">]</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="mi">7</span> <span class="o">+</span> <span class="mi">1</span>
+ <span class="n">age</span><span class="p">,</span> <span class="n">btf</span> <span class="o">=</span> <span class="n">time_range_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s1">&#39;time_range&#39;</span><span class="p">],</span> <span class="p">(</span><span class="s1">&#39;&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">))</span>
+
+ <span class="n">args</span> <span class="o">=</span> <span class="n">urlencode</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;p&#39;</span><span class="p">:</span> <span class="n">query</span><span class="p">,</span>
+ <span class="s1">&#39;ei&#39;</span><span class="p">:</span> <span class="s1">&#39;UTF-8&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;fl&#39;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
+ <span class="s1">&#39;vl&#39;</span><span class="p">:</span> <span class="s1">&#39;lang_&#39;</span> <span class="o">+</span> <span class="n">lang</span><span class="p">,</span>
+ <span class="s1">&#39;btf&#39;</span><span class="p">:</span> <span class="n">btf</span><span class="p">,</span>
+ <span class="s1">&#39;fr2&#39;</span><span class="p">:</span> <span class="s1">&#39;time&#39;</span><span class="p">,</span>
+ <span class="s1">&#39;age&#39;</span><span class="p">:</span> <span class="n">age</span><span class="p">,</span>
+ <span class="s1">&#39;b&#39;</span><span class="p">:</span> <span class="n">offset</span><span class="p">,</span>
+ <span class="s1">&#39;xargs&#39;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="n">domain</span> <span class="o">=</span> <span class="n">lang2domain</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">lang</span><span class="p">,</span> <span class="s1">&#39;</span><span class="si">%s</span><span class="s1">.search.yahoo.com&#39;</span> <span class="o">%</span> <span class="n">lang</span><span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s1">&#39;url&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="s1">&#39;https://</span><span class="si">%s</span><span class="s1">/search?</span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">domain</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">params</span></div>
+
+
+
+<div class="viewcode-block" id="parse_url">
+<a class="viewcode-back" href="../../../dev/engines/online/yahoo.html#searx.engines.yahoo.parse_url">[docs]</a>
+<span class="k">def</span> <span class="nf">parse_url</span><span class="p">(</span><span class="n">url_string</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;remove yahoo-specific tracking-url&quot;&quot;&quot;</span>
+
+ <span class="n">endings</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;/RS&#39;</span><span class="p">,</span> <span class="s1">&#39;/RK&#39;</span><span class="p">]</span>
+ <span class="n">endpositions</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">start</span> <span class="o">=</span> <span class="n">url_string</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">,</span> <span class="n">url_string</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">&#39;/RU=&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">ending</span> <span class="ow">in</span> <span class="n">endings</span><span class="p">:</span>
+ <span class="n">endpos</span> <span class="o">=</span> <span class="n">url_string</span><span class="o">.</span><span class="n">rfind</span><span class="p">(</span><span class="n">ending</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">endpos</span> <span class="o">&gt;</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
+ <span class="n">endpositions</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">endpos</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">start</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">endpositions</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">url_string</span>
+
+ <span class="n">end</span> <span class="o">=</span> <span class="nb">min</span><span class="p">(</span><span class="n">endpositions</span><span class="p">)</span>
+ <span class="k">return</span> <span class="n">unquote</span><span class="p">(</span><span class="n">url_string</span><span class="p">[</span><span class="n">start</span><span class="p">:</span><span class="n">end</span><span class="p">])</span></div>
+
+
+
+<div class="viewcode-block" id="response">
+<a class="viewcode-back" href="../../../dev/engines/online/yahoo.html#searx.engines.yahoo.response">[docs]</a>
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;parse response&quot;&quot;&quot;</span>
+
+ <span class="n">results</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="c1"># parse results</span>
+ <span class="k">for</span> <span class="n">result</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class,&quot;algo-sr&quot;)]&#39;</span><span class="p">):</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//h3/a/@href&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">url</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">url</span> <span class="o">=</span> <span class="n">parse_url</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
+
+ <span class="n">title</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//h3//a/@aria-label&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">title</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">title</span><span class="p">)</span>
+ <span class="n">content</span> <span class="o">=</span> <span class="n">eval_xpath_getindex</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;compText&quot;)]&#39;</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s1">&#39;&#39;</span><span class="p">)</span>
+ <span class="n">content</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">content</span><span class="p">,</span> <span class="n">allow_none</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
+
+ <span class="c1"># append result</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
+ <span class="p">{</span>
+ <span class="s1">&#39;url&#39;</span><span class="p">:</span> <span class="n">url</span><span class="p">,</span>
+ <span class="c1"># title sometimes contains HTML tags / see</span>
+ <span class="c1"># https://github.com/searxng/searxng/issues/3790</span>
+ <span class="s1">&#39;title&#39;</span><span class="p">:</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">html_to_text</span><span class="p">(</span><span class="n">title</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()),</span>
+ <span class="s1">&#39;content&#39;</span><span class="p">:</span> <span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">html_to_text</span><span class="p">(</span><span class="n">content</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">()),</span>
+ <span class="p">}</span>
+ <span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">suggestion</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;AlsoTry&quot;)]//table//a&#39;</span><span class="p">):</span>
+ <span class="c1"># append suggestion</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">({</span><span class="s1">&#39;suggestion&#39;</span><span class="p">:</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">suggestion</span><span class="p">)})</span>
+
+ <span class="k">return</span> <span class="n">results</span></div>
+
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/yahoo.html#searx.engines.yahoo.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">):</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages from yahoo&quot;&quot;&quot;</span>
+
+ <span class="c1"># pylint: disable=import-outside-toplevel</span>
+ <span class="kn">import</span> <span class="nn">babel</span>
+ <span class="kn">from</span> <span class="nn">searx</span> <span class="kn">import</span> <span class="n">network</span>
+ <span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s1">&#39;any&#39;</span>
+
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">network</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;https://search.yahoo.com/preferences/languages&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;ERROR: response from yahoo is not OK.&quot;</span><span class="p">)</span>
+
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+ <span class="n">offset</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="s1">&#39;lang_&#39;</span><span class="p">)</span>
+
+ <span class="n">eng2sxng</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;zh_chs&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hans&#39;</span><span class="p">,</span> <span class="s1">&#39;zh_cht&#39;</span><span class="p">:</span> <span class="s1">&#39;zh_Hant&#39;</span><span class="p">}</span>
+
+ <span class="k">for</span> <span class="n">val</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s1">&#39;//div[contains(@class, &quot;lang-item&quot;)]/input/@value&#39;</span><span class="p">):</span>
+ <span class="n">eng_tag</span> <span class="o">=</span> <span class="n">val</span><span class="p">[</span><span class="n">offset</span><span class="p">:]</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">sxng_tag</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">eng2sxng</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">eng_tag</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">)))</span>
+ <span class="k">except</span> <span class="n">babel</span><span class="o">.</span><span class="n">UnknownLocaleError</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;ERROR: unknown language --&gt; </span><span class="si">%s</span><span class="s1">&#39;</span> <span class="o">%</span> <span class="n">eng_tag</span><span class="p">)</span>
+ <span class="k">continue</span>
+
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_tag</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_tag</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_tag</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_tag</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_tag</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_tag</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file
diff --git a/_modules/searx/engines/zlibrary.html b/_modules/searx/engines/zlibrary.html
new file mode 100644
index 000000000..588e90a8e
--- /dev/null
+++ b/_modules/searx/engines/zlibrary.html
@@ -0,0 +1,366 @@
+<!DOCTYPE html>
+
+<html lang="en" data-content_root="../../../">
+ <head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>searx.engines.zlibrary &#8212; SearXNG Documentation (2025.1.6+6dab7fe78)</title>
+ <link rel="stylesheet" type="text/css" href="../../../_static/pygments.css?v=4f649999" />
+ <link rel="stylesheet" type="text/css" href="../../../_static/searxng.css?v=52e4ff28" />
+ <script src="../../../_static/documentation_options.js?v=ef740023"></script>
+ <script src="../../../_static/doctools.js?v=9a2dae69"></script>
+ <script src="../../../_static/sphinx_highlight.js?v=dc90522c"></script>
+ <script data-project="searxng" data-version="2025.1.6+6dab7fe78" src="../../../_static/describe_version.js?v=fa7f30d0"></script>
+ <link rel="index" title="Index" href="../../../genindex.html" />
+ <link rel="search" title="Search" href="../../../search.html" />
+ </head><body>
+ <div class="related" role="navigation" aria-label="Related">
+ <h3>Navigation</h3>
+ <ul>
+ <li class="right" style="margin-right: 10px">
+ <a href="../../../genindex.html" title="General Index"
+ accesskey="I">index</a></li>
+ <li class="right" >
+ <a href="../../../py-modindex.html" title="Python Module Index"
+ >modules</a> |</li>
+ <li class="nav-item nav-item-0"><a href="../../../index.html">SearXNG Documentation (2025.1.6+6dab7fe78)</a> &#187;</li>
+ <li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
+ <li class="nav-item nav-item-2"><a href="../engines.html" accesskey="U">searx.engines</a> &#187;</li>
+ <li class="nav-item nav-item-this"><a href="">searx.engines.zlibrary</a></li>
+ </ul>
+ </div>
+
+ <div class="document">
+ <div class="documentwrapper">
+ <div class="bodywrapper">
+ <div class="body" role="main">
+
+ <h1>Source code for searx.engines.zlibrary</h1><div class="highlight"><pre>
+<span></span><span class="c1"># SPDX-License-Identifier: AGPL-3.0-or-later</span>
+<span class="sd">&quot;&quot;&quot;`Z-Library`_ (abbreviated as z-lib, formerly BookFinder) is a shadow library</span>
+<span class="sd">project for file-sharing access to scholarly journal articles, academic texts</span>
+<span class="sd">and general-interest books. It began as a mirror of Library Genesis, from which</span>
+<span class="sd">most of its books originate.</span>
+
+<span class="sd">.. _Z-Library: https://zlibrary-global.se/</span>
+
+<span class="sd">Configuration</span>
+<span class="sd">=============</span>
+
+<span class="sd">The engine has the following additional settings:</span>
+
+<span class="sd">- :py:obj:`zlib_year_from`</span>
+<span class="sd">- :py:obj:`zlib_year_to`</span>
+<span class="sd">- :py:obj:`zlib_ext`</span>
+
+<span class="sd">With this options a SearXNG maintainer is able to configure **additional**</span>
+<span class="sd">engines for specific searches in Z-Library. For example a engine to search</span>
+<span class="sd">only for EPUB from 2010 to 2020.</span>
+
+<span class="sd">.. code:: yaml</span>
+
+<span class="sd"> - name: z-library 2010s epub</span>
+<span class="sd"> engine: zlibrary</span>
+<span class="sd"> shortcut: zlib2010s</span>
+<span class="sd"> zlib_year_from: &#39;2010&#39;</span>
+<span class="sd"> zlib_year_to: &#39;2020&#39;</span>
+<span class="sd"> zlib_ext: &#39;EPUB&#39;</span>
+
+<span class="sd">Implementations</span>
+<span class="sd">===============</span>
+
+<span class="sd">&quot;&quot;&quot;</span>
+<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">annotations</span>
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">TYPE_CHECKING</span>
+<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Optional</span>
+<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span>
+<span class="kn">from</span> <span class="nn">urllib.parse</span> <span class="kn">import</span> <span class="n">quote</span>
+<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">html</span>
+<span class="kn">from</span> <span class="nn">flask_babel</span> <span class="kn">import</span> <span class="n">gettext</span>
+
+<span class="kn">from</span> <span class="nn">searx.utils</span> <span class="kn">import</span> <span class="n">extract_text</span><span class="p">,</span> <span class="n">eval_xpath</span><span class="p">,</span> <span class="n">eval_xpath_list</span>
+<span class="kn">from</span> <span class="nn">searx.enginelib.traits</span> <span class="kn">import</span> <span class="n">EngineTraits</span>
+<span class="kn">from</span> <span class="nn">searx.data</span> <span class="kn">import</span> <span class="n">ENGINE_TRAITS</span>
+<span class="kn">from</span> <span class="nn">searx.exceptions</span> <span class="kn">import</span> <span class="n">SearxException</span>
+
+<span class="k">if</span> <span class="n">TYPE_CHECKING</span><span class="p">:</span>
+ <span class="kn">import</span> <span class="nn">httpx</span>
+ <span class="kn">import</span> <span class="nn">logging</span>
+
+ <span class="n">logger</span><span class="p">:</span> <span class="n">logging</span><span class="o">.</span><span class="n">Logger</span>
+
+<span class="c1"># about</span>
+<span class="n">about</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;website&quot;</span><span class="p">:</span> <span class="s2">&quot;https://zlibrary-global.se&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;wikidata_id&quot;</span><span class="p">:</span> <span class="s2">&quot;Q104863992&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;official_api_documentation&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
+ <span class="s2">&quot;use_official_api&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;require_api_key&quot;</span><span class="p">:</span> <span class="kc">False</span><span class="p">,</span>
+ <span class="s2">&quot;results&quot;</span><span class="p">:</span> <span class="s2">&quot;HTML&quot;</span><span class="p">,</span>
+<span class="p">}</span>
+
+<span class="n">categories</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;files&quot;</span><span class="p">]</span>
+<span class="n">paging</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">True</span>
+<span class="n">base_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;https://zlibrary-global.se&quot;</span>
+
+<span class="n">zlib_year_from</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;Filter z-library&#39;s results by year from. E.g &#39;2010&#39;.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">zlib_year_to</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;Filter z-library&#39;s results by year to. E.g. &#39;2010&#39;.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+<span class="n">zlib_ext</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+<span class="sd">&quot;&quot;&quot;Filter z-library&#39;s results by a file ending. Common filters for example are</span>
+<span class="sd">``PDF`` and ``EPUB``.</span>
+<span class="sd">&quot;&quot;&quot;</span>
+
+
+<div class="viewcode-block" id="init">
+<a class="viewcode-back" href="../../../dev/engines/online/zlibrary.html#searx.engines.zlibrary.init">[docs]</a>
+<span class="k">def</span> <span class="nf">init</span><span class="p">(</span><span class="n">engine_settings</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span> <span class="c1"># pylint: disable=unused-argument</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Check of engine&#39;s settings.&quot;&quot;&quot;</span>
+ <span class="n">traits</span><span class="p">:</span> <span class="n">EngineTraits</span> <span class="o">=</span> <span class="n">EngineTraits</span><span class="p">(</span><span class="o">**</span><span class="n">ENGINE_TRAITS</span><span class="p">[</span><span class="s2">&quot;z-library&quot;</span><span class="p">])</span>
+
+ <span class="k">if</span> <span class="n">zlib_ext</span> <span class="ow">and</span> <span class="n">zlib_ext</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ext&quot;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;invalid setting ext: </span><span class="si">{</span><span class="n">zlib_ext</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">zlib_year_from</span> <span class="ow">and</span> <span class="n">zlib_year_from</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_from&quot;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;invalid setting year_from: </span><span class="si">{</span><span class="n">zlib_year_from</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">zlib_year_to</span> <span class="ow">and</span> <span class="n">zlib_year_to</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_to&quot;</span><span class="p">]:</span>
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;invalid setting year_to: </span><span class="si">{</span><span class="n">zlib_year_to</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
+
+
+
+<span class="k">def</span> <span class="nf">request</span><span class="p">(</span><span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">params</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
+ <span class="n">lang</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">traits</span><span class="o">.</span><span class="n">get_language</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;language&quot;</span><span class="p">],</span> <span class="n">traits</span><span class="o">.</span><span class="n">all_locale</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+ <span class="n">search_url</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="p">(</span>
+ <span class="n">base_url</span>
+ <span class="o">+</span> <span class="s2">&quot;/s/</span><span class="si">{search_query}</span><span class="s2">/?page=</span><span class="si">{pageno}</span><span class="s2">&quot;</span>
+ <span class="o">+</span> <span class="s2">&quot;&amp;yearFrom=</span><span class="si">{zlib_year_from}</span><span class="s2">&quot;</span>
+ <span class="o">+</span> <span class="s2">&quot;&amp;yearTo=</span><span class="si">{zlib_year_to}</span><span class="s2">&quot;</span>
+ <span class="o">+</span> <span class="s2">&quot;&amp;languages[]=</span><span class="si">{lang}</span><span class="s2">&quot;</span>
+ <span class="o">+</span> <span class="s2">&quot;&amp;extensions[]=</span><span class="si">{zlib_ext}</span><span class="s2">&quot;</span>
+ <span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;url&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">search_url</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
+ <span class="n">search_query</span><span class="o">=</span><span class="n">quote</span><span class="p">(</span><span class="n">query</span><span class="p">),</span>
+ <span class="n">pageno</span><span class="o">=</span><span class="n">params</span><span class="p">[</span><span class="s2">&quot;pageno&quot;</span><span class="p">],</span>
+ <span class="n">lang</span><span class="o">=</span><span class="n">lang</span><span class="p">,</span>
+ <span class="n">zlib_year_from</span><span class="o">=</span><span class="n">zlib_year_from</span><span class="p">,</span>
+ <span class="n">zlib_year_to</span><span class="o">=</span><span class="n">zlib_year_to</span><span class="p">,</span>
+ <span class="n">zlib_ext</span><span class="o">=</span><span class="n">zlib_ext</span><span class="p">,</span>
+ <span class="p">)</span>
+ <span class="n">params</span><span class="p">[</span><span class="s2">&quot;verify&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="kc">False</span>
+ <span class="k">return</span> <span class="n">params</span>
+
+
+<span class="k">def</span> <span class="nf">domain_is_seized</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="k">return</span> <span class="nb">bool</span><span class="p">(</span><span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//title&#39;</span><span class="p">)</span> <span class="ow">and</span> <span class="s2">&quot;seized&quot;</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//title&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">lower</span><span class="p">())</span>
+
+
+<span class="k">def</span> <span class="nf">response</span><span class="p">(</span><span class="n">resp</span><span class="p">:</span> <span class="n">httpx</span><span class="o">.</span><span class="n">Response</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]:</span>
+ <span class="n">results</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span>
+
+ <span class="k">if</span> <span class="n">domain_is_seized</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="k">raise</span> <span class="n">SearxException</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;zlibrary domain is seized: </span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+
+ <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">dom</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;//div[@id=&quot;searchResultBox&quot;]//div[contains(@class, &quot;resItemBox&quot;)]&#39;</span><span class="p">):</span>
+ <span class="n">results</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">_parse_result</span><span class="p">(</span><span class="n">item</span><span class="p">))</span>
+
+ <span class="k">return</span> <span class="n">results</span>
+
+
+<span class="k">def</span> <span class="nf">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">selector</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">return</span> <span class="n">extract_text</span><span class="p">(</span><span class="n">eval_xpath</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">selector</span><span class="p">))</span>
+
+
+<span class="n">i18n_language</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;Language&quot;</span><span class="p">)</span>
+<span class="n">i18n_book_rating</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;Book rating&quot;</span><span class="p">)</span>
+<span class="n">i18n_file_quality</span> <span class="o">=</span> <span class="n">gettext</span><span class="p">(</span><span class="s2">&quot;File quality&quot;</span><span class="p">)</span>
+
+
+<span class="k">def</span> <span class="nf">_parse_result</span><span class="p">(</span><span class="n">item</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
+
+ <span class="n">author_elements</span> <span class="o">=</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[@class=&quot;authors&quot;]//a[@itemprop=&quot;author&quot;]&#39;</span><span class="p">)</span>
+
+ <span class="n">result</span> <span class="o">=</span> <span class="p">{</span>
+ <span class="s2">&quot;template&quot;</span><span class="p">:</span> <span class="s2">&quot;paper.html&quot;</span><span class="p">,</span>
+ <span class="s2">&quot;url&quot;</span><span class="p">:</span> <span class="n">base_url</span> <span class="o">+</span> <span class="n">item</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">&#39;(.//a[starts-with(@href, &quot;/book/&quot;)])[1]/@href&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">],</span>
+ <span class="s2">&quot;title&quot;</span><span class="p">:</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//*[@itemprop=&quot;name&quot;]&#39;</span><span class="p">),</span>
+ <span class="s2">&quot;authors&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">extract_text</span><span class="p">(</span><span class="n">author</span><span class="p">)</span> <span class="k">for</span> <span class="n">author</span> <span class="ow">in</span> <span class="n">author_elements</span><span class="p">],</span>
+ <span class="s2">&quot;publisher&quot;</span><span class="p">:</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//a[@title=&quot;Publisher&quot;]&#39;</span><span class="p">),</span>
+ <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;property__file&quot;)]//div[contains(@class, &quot;property_value&quot;)]&#39;</span><span class="p">),</span>
+ <span class="p">}</span>
+
+ <span class="n">thumbnail</span> <span class="o">=</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//img[contains(@class, &quot;cover&quot;)]/@data-src&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">thumbnail</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">):</span>
+ <span class="n">result</span><span class="p">[</span><span class="s2">&quot;thumbnail&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">thumbnail</span>
+
+ <span class="n">year</span> <span class="o">=</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;property_year&quot;)]//div[contains(@class, &quot;property_value&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">year</span><span class="p">:</span>
+ <span class="n">result</span><span class="p">[</span><span class="s2">&quot;publishedDate&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">year</span><span class="p">,</span> <span class="s1">&#39;%Y&#39;</span><span class="p">)</span>
+
+ <span class="n">content</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">language</span> <span class="o">=</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//div[contains(@class, &quot;property_language&quot;)]//div[contains(@class, &quot;property_value&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">language</span><span class="p">:</span>
+ <span class="n">content</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">i18n_language</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">language</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">book_rating</span> <span class="o">=</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//span[contains(@class, &quot;book-rating-interest-score&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">book_rating</span> <span class="ow">and</span> <span class="nb">float</span><span class="p">(</span><span class="n">book_rating</span><span class="p">):</span>
+ <span class="n">content</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">i18n_book_rating</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">book_rating</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">file_quality</span> <span class="o">=</span> <span class="n">_text</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s1">&#39;.//span[contains(@class, &quot;book-rating-quality-score&quot;)]&#39;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">file_quality</span> <span class="ow">and</span> <span class="nb">float</span><span class="p">(</span><span class="n">file_quality</span><span class="p">):</span>
+ <span class="n">content</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">i18n_file_quality</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">file_quality</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">result</span><span class="p">[</span><span class="s2">&quot;content&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot; | &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">content</span><span class="p">)</span>
+
+ <span class="k">return</span> <span class="n">result</span>
+
+
+<div class="viewcode-block" id="fetch_traits">
+<a class="viewcode-back" href="../../../dev/engines/online/zlibrary.html#searx.engines.zlibrary.fetch_traits">[docs]</a>
+<span class="k">def</span> <span class="nf">fetch_traits</span><span class="p">(</span><span class="n">engine_traits</span><span class="p">:</span> <span class="n">EngineTraits</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
+<span class="w"> </span><span class="sd">&quot;&quot;&quot;Fetch languages and other search arguments from zlibrary&#39;s search form.&quot;&quot;&quot;</span>
+ <span class="c1"># pylint: disable=import-outside-toplevel, too-many-branches</span>
+
+ <span class="kn">import</span> <span class="nn">babel</span>
+ <span class="kn">from</span> <span class="nn">searx.network</span> <span class="kn">import</span> <span class="n">get</span> <span class="c1"># see https://github.com/searxng/searxng/issues/762</span>
+ <span class="kn">from</span> <span class="nn">searx.locales</span> <span class="kn">import</span> <span class="n">language_tag</span>
+
+ <span class="k">def</span> <span class="nf">_use_old_values</span><span class="p">():</span>
+ <span class="c1"># don&#39;t change anything, re-use the existing values</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="n">ENGINE_TRAITS</span><span class="p">[</span><span class="s2">&quot;z-library&quot;</span><span class="p">][</span><span class="s2">&quot;all_locale&quot;</span><span class="p">]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span> <span class="o">=</span> <span class="n">ENGINE_TRAITS</span><span class="p">[</span><span class="s2">&quot;z-library&quot;</span><span class="p">][</span><span class="s2">&quot;custom&quot;</span><span class="p">]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span> <span class="o">=</span> <span class="n">ENGINE_TRAITS</span><span class="p">[</span><span class="s2">&quot;z-library&quot;</span><span class="p">][</span><span class="s2">&quot;languages&quot;</span><span class="p">]</span>
+
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">resp</span> <span class="o">=</span> <span class="n">get</span><span class="p">(</span><span class="n">base_url</span><span class="p">,</span> <span class="n">verify</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
+ <span class="k">except</span> <span class="n">SearxException</span> <span class="k">as</span> <span class="n">exc</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ERROR: zlibrary domain &#39;</span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">&#39; is seized?&quot;</span><span class="p">)</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; --&gt; </span><span class="si">{</span><span class="n">exc</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">_use_old_values</span><span class="p">()</span>
+ <span class="k">return</span>
+
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">resp</span><span class="o">.</span><span class="n">ok</span><span class="p">:</span> <span class="c1"># type: ignore</span>
+ <span class="k">raise</span> <span class="ne">RuntimeError</span><span class="p">(</span><span class="s2">&quot;Response from zlibrary&#39;s search page is not OK.&quot;</span><span class="p">)</span>
+ <span class="n">dom</span> <span class="o">=</span> <span class="n">html</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">resp</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">if</span> <span class="n">domain_is_seized</span><span class="p">(</span><span class="n">dom</span><span class="p">):</span>
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ERROR: zlibrary domain is seized: </span><span class="si">{</span><span class="n">base_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
+ <span class="n">_use_old_values</span><span class="p">()</span>
+ <span class="k">return</span>
+
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">all_locale</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ext&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_from&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_to&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
+
+ <span class="k">for</span> <span class="n">year</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//div[@id=&#39;advSearch-noJS&#39;]//select[@id=&#39;sf_yearFrom&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_from&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">year</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="n">year</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//div[@id=&#39;advSearch-noJS&#39;]//select[@id=&#39;sf_yearTo&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;year_to&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">year</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">))</span>
+
+ <span class="k">for</span> <span class="n">ext</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//div[@id=&#39;advSearch-noJS&#39;]//select[@id=&#39;sf_extensions&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">value</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="n">ext</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="n">value</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">custom</span><span class="p">[</span><span class="s2">&quot;ext&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
+
+ <span class="c1"># Handle languages</span>
+ <span class="c1"># Z-library uses English names for languages, so we need to map them to their respective locales</span>
+ <span class="n">language_name_locale_map</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
+ <span class="k">for</span> <span class="n">locale</span> <span class="ow">in</span> <span class="n">babel</span><span class="o">.</span><span class="n">core</span><span class="o">.</span><span class="n">localedata</span><span class="o">.</span><span class="n">locale_identifiers</span><span class="p">():</span> <span class="c1"># type: ignore</span>
+ <span class="c1"># Create a Locale object for the current locale</span>
+ <span class="n">loc</span> <span class="o">=</span> <span class="n">babel</span><span class="o">.</span><span class="n">Locale</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">locale</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">loc</span><span class="o">.</span><span class="n">english_name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="n">language_name_locale_map</span><span class="p">[</span><span class="n">loc</span><span class="o">.</span><span class="n">english_name</span><span class="o">.</span><span class="n">lower</span><span class="p">()]</span> <span class="o">=</span> <span class="n">loc</span> <span class="c1"># type: ignore</span>
+
+ <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">eval_xpath_list</span><span class="p">(</span><span class="n">dom</span><span class="p">,</span> <span class="s2">&quot;//div[@id=&#39;advSearch-noJS&#39;]//select[@id=&#39;sf_languages&#39;]/option&quot;</span><span class="p">):</span>
+ <span class="n">eng_lang</span> <span class="o">=</span> <span class="n">x</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;value&quot;</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">eng_lang</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
+ <span class="k">continue</span>
+ <span class="k">try</span><span class="p">:</span>
+ <span class="n">locale</span> <span class="o">=</span> <span class="n">language_name_locale_map</span><span class="p">[</span><span class="n">eng_lang</span><span class="o">.</span><span class="n">lower</span><span class="p">()]</span>
+ <span class="k">except</span> <span class="ne">KeyError</span><span class="p">:</span>
+ <span class="c1"># silently ignore unknown languages</span>
+ <span class="c1"># print(&quot;ERROR: %s is unknown by babel&quot; % (eng_lang))</span>
+ <span class="k">continue</span>
+ <span class="n">sxng_lang</span> <span class="o">=</span> <span class="n">language_tag</span><span class="p">(</span><span class="n">locale</span><span class="p">)</span>
+ <span class="n">conflict</span> <span class="o">=</span> <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">sxng_lang</span><span class="p">)</span>
+ <span class="k">if</span> <span class="n">conflict</span><span class="p">:</span>
+ <span class="k">if</span> <span class="n">conflict</span> <span class="o">!=</span> <span class="n">eng_lang</span><span class="p">:</span>
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;CONFLICT: babel </span><span class="si">%s</span><span class="s2"> --&gt; </span><span class="si">%s</span><span class="s2">, </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">sxng_lang</span><span class="p">,</span> <span class="n">conflict</span><span class="p">,</span> <span class="n">eng_lang</span><span class="p">))</span>
+ <span class="k">continue</span>
+ <span class="n">engine_traits</span><span class="o">.</span><span class="n">languages</span><span class="p">[</span><span class="n">sxng_lang</span><span class="p">]</span> <span class="o">=</span> <span class="n">eng_lang</span></div>
+
+</pre></div>
+
+ <div class="clearer"></div>
+ </div>
+ </div>
+ </div>
+ <span id="sidebar-top"></span>
+ <div class="sphinxsidebar" role="navigation" aria-label="Main">
+ <div class="sphinxsidebarwrapper">
+
+
+ <p class="logo"><a href="../../../index.html">
+ <img class="logo" src="../../../_static/searxng-wordmark.svg" alt="Logo of SearXNG"/>
+ </a></p>
+
+
+<h3><a href="../../../index.html">Table of Contents</a></h3>
+<ul>
+<li class="toctree-l1"><a class="reference internal" href="../../../user/index.html">User information</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../own-instance.html">Why use a private instance?</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../admin/index.html">Administrator documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../dev/index.html">Developer documentation</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../utils/index.html">DevOps tooling box</a></li>
+<li class="toctree-l1"><a class="reference internal" href="../../../src/index.html">Source-Code</a></li>
+</ul>
+
+ <h3>Project Links</h3>
+ <ul>
+ <li><a href="https://github.com/searxng/searxng/tree/master">Source</a>
+
+ <li><a href="https://github.com/searxng/searxng/wiki">Wiki</a>
+
+ <li><a href="https://searx.space">Public instances</a>
+
+ <li><a href="https://github.com/searxng/searxng/issues">Issue Tracker</a>
+ </ul><h3>Navigation</h3>
+<ul>
+ <li><a href="../../../index.html">Overview</a>
+ <ul>
+ <li><a href="../../index.html">Module code</a>
+ <ul>
+ <li><a href="../engines.html">searx.engines</a>
+
+
+ </ul>
+ </li></ul>
+ </li>
+ </ul>
+ </li>
+</ul>
+<search id="searchbox" style="display: none" role="search">
+ <h3 id="searchlabel">Quick search</h3>
+ <div class="searchformwrapper">
+ <form class="search" action="../../../search.html" method="get">
+ <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
+ <input type="submit" value="Go" />
+ </form>
+ </div>
+</search>
+<script>document.getElementById('searchbox').style.display = "block"</script>
+ </div>
+ </div>
+ <div class="clearer"></div>
+ </div>
+ <div class="footer" role="contentinfo">
+ &#169; Copyright SearXNG team.
+ </div>
+ </body>
+</html> \ No newline at end of file