mirror of
https://github.com/searxng/searxng.git
synced 2026-08-14 11:11:27 +00:00
Compare commits
10 Commits
translatio
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32abcac41f | ||
|
|
ef9a188cc8 | ||
|
|
cdfdaa5a88 | ||
|
|
5638231358 | ||
|
|
1c3bb1e88f | ||
|
|
54613defc7 | ||
|
|
e8e710e42a | ||
|
|
7b0c7f0bf8 | ||
|
|
e033be7c7c | ||
|
|
0a118066d8 |
8
.github/workflows/container.yml
vendored
8
.github/workflows/container.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2
|
||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: "${{ github.repository_owner }}"
|
||||
@@ -110,7 +110,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2
|
||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: "${{ github.repository_owner }}"
|
||||
@@ -144,14 +144,14 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2
|
||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
with:
|
||||
registry: "docker.io"
|
||||
username: "${{ secrets.DOCKER_USER }}"
|
||||
password: "${{ secrets.DOCKER_TOKEN }}"
|
||||
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@371161bbe7024a29a25c5e19bfcbc0804fe9ad2c # v4.5.2
|
||||
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
|
||||
with:
|
||||
registry: "ghcr.io"
|
||||
username: "${{ github.repository_owner }}"
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
search:
|
||||
safe_search: 0
|
||||
autocomplete: ""
|
||||
autocomplete: "duckduckgo"
|
||||
favicon_resolver: ""
|
||||
default_lang: ""
|
||||
ban_time_on_fail: 5
|
||||
@@ -32,7 +32,7 @@
|
||||
- ``2``: Strict
|
||||
|
||||
``autocomplete``:
|
||||
Existing autocomplete backends, leave blank to turn it off.
|
||||
Existing autocomplete backends, set blank to turn it off.
|
||||
|
||||
- ``360search``
|
||||
- ``baidu``
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
limiter: false
|
||||
public_instance: false
|
||||
image_proxy: false
|
||||
method: "POST"
|
||||
method: "GET"
|
||||
default_http_headers:
|
||||
X-Content-Type-Options : nosniff
|
||||
X-Download-Options : noopen
|
||||
@@ -58,8 +58,8 @@
|
||||
|
||||
``method`` : ``GET`` | ``POST``
|
||||
|
||||
HTTP method. By defaults ``POST`` is used / The ``POST`` method has the
|
||||
advantage with some WEB browsers that the history is not easy to read, but
|
||||
HTTP method. By default, ``GET`` is used / The ``POST`` method has the
|
||||
advantage with some browsers that the history is not saved, but
|
||||
there are also various disadvantages that sometimes **severely restrict the
|
||||
ease of use for the end user** (e.g. back button to jump back to the previous
|
||||
search page and drag & drop of search term to new tabs do not work as
|
||||
|
||||
8
docs/dev/engines/online/jina.rst
Normal file
8
docs/dev/engines/online/jina.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _jina engine:
|
||||
|
||||
===========
|
||||
Jina Engine
|
||||
===========
|
||||
|
||||
.. automodule:: searx.engines.jina
|
||||
:members:
|
||||
8
docs/dev/engines/online/yandex_api.rst
Normal file
8
docs/dev/engines/online/yandex_api.rst
Normal file
@@ -0,0 +1,8 @@
|
||||
.. _yandex api engine:
|
||||
|
||||
=================
|
||||
Yandex Search API
|
||||
=================
|
||||
|
||||
.. automodule:: searx.engines.yandex_api
|
||||
:members:
|
||||
@@ -2,9 +2,9 @@ mock==5.2.0
|
||||
nose2[coverage_plugin]==0.16.0
|
||||
cov-core==1.15.0
|
||||
black==25.9.0
|
||||
pylint==4.0.6
|
||||
pylint==4.0.7
|
||||
splinter==0.21.0
|
||||
selenium==4.46.0
|
||||
selenium==4.47.0
|
||||
Sphinx==8.2.3;python_version <= "3.11"
|
||||
Sphinx==9.1.0; python_version > "3.11"
|
||||
sphinx-issues==6.0.0
|
||||
@@ -18,11 +18,11 @@ myst-parser==5.0.0
|
||||
linuxdoc==20260504
|
||||
aiounittest==1.5.0
|
||||
yamllint==1.38.0
|
||||
wlc==2.1.0
|
||||
wlc==2.1.1
|
||||
coloredlogs==15.0.1
|
||||
docutils>=0.21.2;python_version <= "3.11"
|
||||
docutils>=0.22.4; python_version > "3.11"
|
||||
parameterized==0.9.0
|
||||
granian[reload]==2.7.9
|
||||
granian[reload]==2.8.1
|
||||
basedpyright==1.39.9
|
||||
types-lxml==2026.2.16
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
granian==2.7.9
|
||||
granian[pname]==2.7.9
|
||||
granian==2.8.1
|
||||
granian[pname]==2.8.1
|
||||
|
||||
@@ -13,7 +13,7 @@ sniffio==1.3.1
|
||||
valkey==6.1.1
|
||||
markdown-it-py==4.2.0
|
||||
msgspec==0.21.1
|
||||
typer==0.27.0
|
||||
typer==0.27.1
|
||||
isodate==0.7.2
|
||||
whitenoise==6.12.0
|
||||
typing-extensions==4.16.0
|
||||
|
||||
@@ -43,9 +43,10 @@ def init(_):
|
||||
|
||||
def request(query: str, params: "OnlineParams"):
|
||||
params["url"] = f"{base_url}/api/{dogpile_categ}"
|
||||
params["headers"]["Origin"] = base_url
|
||||
|
||||
params["method"] = "POST"
|
||||
params["json"] = {"q": query, "qadf": safe_search_map[params["safesearch"]], "page": params["pageno"]}
|
||||
return params
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response"):
|
||||
|
||||
89
searx/engines/jina.py
Normal file
89
searx/engines/jina.py
Normal file
@@ -0,0 +1,89 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Jina is a search AI and part of Elastic, the company behind ElasticSearch.
|
||||
|
||||
The engine requires an API key, you can get one from the
|
||||
`API dashboard <https://jina.ai/api-dashboard/>`_ without signup.
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- name: jina
|
||||
engine: jina
|
||||
shortcut: ji
|
||||
api_key: "jina_..."
|
||||
jina_engine: reader
|
||||
inactive: false
|
||||
|
||||
By default, Jina's own index is used. You can change that by setting a different :py:obj:`jina_engine`.
|
||||
"""
|
||||
|
||||
import typing as t
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from dateutil import parser
|
||||
from searx.result_types import EngineResults
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from searx.extended_types import SXNG_Response
|
||||
from searx.search.processors import OnlineParams
|
||||
|
||||
|
||||
about = {
|
||||
"website": "https://jina.ai",
|
||||
"wikidata_id": None,
|
||||
"official_api_documentation": "https://s.jina.ai/docs",
|
||||
"use_official_api": True,
|
||||
"require_api_key": True,
|
||||
"results": "JSON",
|
||||
}
|
||||
|
||||
categories = ["general"]
|
||||
paging = True
|
||||
|
||||
jina_engine = "reader"
|
||||
"""Search mode. Currently supported values are 'reader', 'google' and 'bing'."""
|
||||
|
||||
base_url = "https://s.jina.ai"
|
||||
api_key: str | None = None
|
||||
|
||||
|
||||
def setup(_):
|
||||
if not api_key:
|
||||
raise ValueError("missing api key")
|
||||
|
||||
|
||||
def request(query: str, params: "OnlineParams"):
|
||||
# setting 'no-content' pushes the response time down to a third
|
||||
args = {"q": query, "page": params["pageno"], "engine": jina_engine, "respondWith": "no-content"}
|
||||
params["url"] = f"{base_url}/?{urlencode(args)}"
|
||||
params["headers"].update(
|
||||
{
|
||||
"Accept": "application/json",
|
||||
"Authorization": f"Bearer {api_key}",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response"):
|
||||
res = EngineResults()
|
||||
|
||||
json_resp: dict[str, t.Any] = resp.json()
|
||||
|
||||
result: dict[str, str]
|
||||
for result in json_resp["data"]:
|
||||
published_date = None
|
||||
if result.get("date"):
|
||||
try:
|
||||
published_date = parser.parse(result["date"])
|
||||
except parser.ParserError:
|
||||
pass
|
||||
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=result["url"],
|
||||
title=result["title"],
|
||||
content=result["description"],
|
||||
publishedDate=published_date,
|
||||
)
|
||||
)
|
||||
|
||||
return res
|
||||
217
searx/engines/yandex_api.py
Normal file
217
searx/engines/yandex_api.py
Normal file
@@ -0,0 +1,217 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Yandex Search API (the official **paid** `Yandex Search API v2`_).
|
||||
|
||||
Unlike the :origin:`yandex <searx/engines/yandex.py>` engine (which scrapes the
|
||||
public HTML interface and is prone to CAPTCHA blocking), this engine talks to
|
||||
the official, paid Yandex Cloud Search API. It requires a Yandex Cloud account,
|
||||
a *folder id* and an *API key*.
|
||||
|
||||
The API answers with a Base64-encoded XML document, which is decoded and
|
||||
parsed here.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
The engine is inactive by default because it needs credentials. To enable it,
|
||||
set ``inactive: false`` and add your ``api_key`` and ``yandex_folder_id`` to
|
||||
:origin:`searx/settings.yml`:
|
||||
|
||||
.. code:: yaml
|
||||
|
||||
- name: yandex api
|
||||
engine: yandex_api
|
||||
shortcut: yda
|
||||
categories: [general, web]
|
||||
inactive: false
|
||||
api_key: "" # Yandex Cloud API key (``Api-Key``)
|
||||
yandex_folder_id: "" # Yandex Cloud folder id
|
||||
# optional, see below:
|
||||
yandex_default_language: en
|
||||
|
||||
.. _Yandex Search API v2:
|
||||
https://aistudio.yandex.ru/docs/en/search-api/api-ref/WebSearch/search.html
|
||||
"""
|
||||
|
||||
import math
|
||||
import typing as t
|
||||
from base64 import b64decode
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from searx.exceptions import SearxEngineAPIException
|
||||
from searx.result_types import EngineResults
|
||||
from searx.utils import extract_text
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from searx.extended_types import SXNG_Response
|
||||
from searx.search.processors import OnlineParams
|
||||
|
||||
|
||||
about = {
|
||||
"website": "https://yandex.cloud/en/services/search-api",
|
||||
"wikidata_id": "Q5281",
|
||||
"official_api_documentation": "https://aistudio.yandex.ru/docs/en/search-api/api-ref/WebSearch/search.html",
|
||||
"use_official_api": True,
|
||||
"require_api_key": True,
|
||||
"results": "XML",
|
||||
}
|
||||
|
||||
# Engine configuration
|
||||
categories = ["general", "web"]
|
||||
paging = True
|
||||
safesearch = True
|
||||
|
||||
# Credentials, overwritten via settings.yml
|
||||
api_key: str = ""
|
||||
"""Yandex Cloud API key, passed as ``Authorization: Api-Key <api_key>``."""
|
||||
|
||||
yandex_folder_id: str = ""
|
||||
"""Yandex Cloud folder id the API key belongs to."""
|
||||
|
||||
# Search tuning, overwritten via settings.yml
|
||||
yandex_default_language: str = "en"
|
||||
"""Default query language. It selects the Yandex search domain (e.g. yandex.ru
|
||||
for ``ru``, yandex.com for ``en``) and the language of the search-result
|
||||
notifications, but only as a fallback -- a request whose own locale matches
|
||||
:py:obj:`language_map` overrides it. Must be one of its keys: ``ru``, ``be``,
|
||||
``kk``, ``uk``, ``tr`` or ``en``."""
|
||||
|
||||
region: str = ""
|
||||
"""Optional Yandex `region id`.
|
||||
Only meaningful together with ``SEARCH_TYPE_RU``.
|
||||
|
||||
__ https://aistudio.yandex.ru/docs/en/search-api/reference/regions.html
|
||||
"""
|
||||
|
||||
page_size: int = 10
|
||||
"""Number of results requested per page."""
|
||||
|
||||
base_url = "https://searchapi.api.cloud.yandex.net/v2/web/search"
|
||||
|
||||
# searxng safesearch level -> Yandex familyMode
|
||||
safesearch_map = {
|
||||
0: "FAMILY_MODE_NONE",
|
||||
1: "FAMILY_MODE_MODERATE",
|
||||
2: "FAMILY_MODE_STRICT",
|
||||
}
|
||||
|
||||
# Map a query language to a (search_type, l10n) pair. It drives both the
|
||||
# per-request override (when the query's locale matches) and the
|
||||
# ``yandex_default_language`` default.
|
||||
language_map = {
|
||||
"ru": ("SEARCH_TYPE_RU", "LOCALIZATION_RU"),
|
||||
"be": ("SEARCH_TYPE_BE", "LOCALIZATION_BE"),
|
||||
"kk": ("SEARCH_TYPE_KK", "LOCALIZATION_KK"),
|
||||
"uk": ("SEARCH_TYPE_RU", "LOCALIZATION_UK"),
|
||||
"tr": ("SEARCH_TYPE_TR", "LOCALIZATION_TR"),
|
||||
"en": ("SEARCH_TYPE_COM", "LOCALIZATION_EN"),
|
||||
# Uzbek ('uz') is intentionally omitted: Yandex offers SEARCH_TYPE_UZ but no
|
||||
# matching LOCALIZATION_UZ, so such queries fall back to the defaults above.
|
||||
}
|
||||
|
||||
|
||||
def setup(_):
|
||||
"""Validate credentials and paging limits when the engine is loaded."""
|
||||
if not api_key or not yandex_folder_id:
|
||||
raise SearxEngineAPIException("missing 'api_key' and/or 'yandex_folder_id' in engine settings")
|
||||
if not 1 <= page_size <= 100:
|
||||
raise SearxEngineAPIException("'page_size' must be in the range 1..100 (Yandex 'groupsOnPage')")
|
||||
if yandex_default_language not in language_map:
|
||||
raise SearxEngineAPIException(f"'yandex_default_language' must be one of {sorted(language_map)}")
|
||||
|
||||
|
||||
def request(query: str, params: "OnlineParams"):
|
||||
|
||||
# Yandex returns at most 250 results for a query.
|
||||
max_page = math.ceil(250 / page_size)
|
||||
if params["pageno"] > max_page:
|
||||
params["url"] = None
|
||||
return
|
||||
|
||||
if len(query) > 400:
|
||||
# Yandex rejects a 'queryText' longer than 400 characters; decline the
|
||||
# request gracefully instead of provoking an API error.
|
||||
params["url"] = None
|
||||
return
|
||||
|
||||
lang = params["searxng_locale"].split("-")[0].lower()
|
||||
req_search_type, req_l10n = language_map.get(lang, language_map[yandex_default_language])
|
||||
|
||||
body: dict[str, t.Any] = {
|
||||
"query": {
|
||||
"searchType": req_search_type,
|
||||
"queryText": query,
|
||||
"familyMode": safesearch_map[params["safesearch"]],
|
||||
# the API uses a 0-based page index
|
||||
"page": str(params["pageno"] - 1),
|
||||
},
|
||||
"groupSpec": {
|
||||
"groupMode": "GROUP_MODE_FLAT",
|
||||
"groupsOnPage": str(page_size),
|
||||
"docsInGroup": "1",
|
||||
},
|
||||
"l10n": req_l10n,
|
||||
"folderId": yandex_folder_id,
|
||||
"responseFormat": "FORMAT_XML",
|
||||
}
|
||||
# Yandex accepts a 'region' only together with the Russian search type.
|
||||
if region and req_search_type == "SEARCH_TYPE_RU":
|
||||
body["region"] = region
|
||||
|
||||
params["method"] = "POST"
|
||||
params["url"] = base_url
|
||||
params["headers"]["Authorization"] = f"Api-Key {api_key}"
|
||||
params["headers"]["Content-Type"] = "application/json"
|
||||
params["json"] = body
|
||||
|
||||
|
||||
def _raw_xml(resp: "SXNG_Response") -> bytes:
|
||||
"""Extract and Base64-decode the XML payload out of the JSON envelope.
|
||||
|
||||
The synchronous ``/v2/web/search`` endpoint returns ``{"rawData":
|
||||
"<base64>"}`` on success; HTTP errors are raised upstream via
|
||||
``raise_for_httperror``.
|
||||
"""
|
||||
data: dict[str, t.Any] = resp.json()
|
||||
|
||||
raw_data = data.get("rawData")
|
||||
if raw_data is None:
|
||||
raise SearxEngineAPIException("Yandex Search API: no 'rawData' in response")
|
||||
|
||||
return b64decode(raw_data)
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
res = EngineResults()
|
||||
|
||||
dom = etree.fromstring(_raw_xml(resp)) # pylint: disable=c-extension-no-member
|
||||
|
||||
# An <error> inside <response> signals an application error. Code 15 simply
|
||||
# means "nothing was found" and must not raise.
|
||||
error = dom.find(".//response/error")
|
||||
if error is not None:
|
||||
if error.get("code") == "15":
|
||||
return res
|
||||
raise SearxEngineAPIException(f"Yandex Search API error {error.get('code')}: {error.text}")
|
||||
|
||||
for doc in dom.iterfind(".//doc"):
|
||||
url = extract_text(doc.find("url"), allow_none=True)
|
||||
title = extract_text(doc.find("title"), allow_none=True)
|
||||
if not url or not title:
|
||||
continue
|
||||
|
||||
content = extract_text(doc.find("headline"), allow_none=True)
|
||||
if not content:
|
||||
passages = doc.find("passages")
|
||||
if passages is not None:
|
||||
content = " ".join(extract_text(p) or "" for p in passages.iterfind("passage")).strip()
|
||||
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=url,
|
||||
title=title,
|
||||
content=content or "",
|
||||
)
|
||||
)
|
||||
|
||||
return res
|
||||
@@ -41,9 +41,9 @@ search:
|
||||
# Filter results. 0: None, 1: Moderate, 2: Strict
|
||||
safe_search: 0
|
||||
# Existing autocomplete backends: "360search", "baidu", "bing", "brave", "dbpedia", "duckduckgo", "google",
|
||||
# "kagi", "yandex", "privacywall", "mwmbl", "naver", "seznam", "sogou", "startpage", "swisscows", "quark",
|
||||
# "qwant", "wikipedia" - leave blank to turn it off by default.
|
||||
autocomplete: ""
|
||||
# "yandex", "privacywall", "mwmbl", "naver", "seznam", "sogou", "startpage", "swisscows", "quark", "qwant",
|
||||
# "wikipedia" - set blank to turn it off by default.
|
||||
autocomplete: "duckduckgo"
|
||||
# minimun characters to type before autocompleter starts
|
||||
autocomplete_min: 4
|
||||
# backend for the favicon near URL in search results.
|
||||
@@ -107,11 +107,10 @@ server:
|
||||
image_proxy: false
|
||||
# 1.0 and 1.1 are supported
|
||||
http_protocol_version: "1.0"
|
||||
# POST queries are "more secure!" but are also the source of hard-to-locate
|
||||
# annoyances, which is why GET may be better for end users and their browsers.
|
||||
# POST keeps search queries out of the browsers history, but causes UX issues.
|
||||
# see https://github.com/searxng/searxng/pull/3619
|
||||
# Is overwritten by ${SEARXNG_METHOD}
|
||||
method: "POST"
|
||||
method: "GET"
|
||||
default_http_headers:
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Download-Options: noopen
|
||||
@@ -853,28 +852,28 @@ engines:
|
||||
shortcut: dog
|
||||
dogpile_categ: search
|
||||
categories: general
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: dogpile images
|
||||
engine: dogpile
|
||||
shortcut: dogi
|
||||
dogpile_categ: images
|
||||
categories: images
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: dogpile videos
|
||||
engine: dogpile
|
||||
shortcut: dogv
|
||||
dogpile_categ: videos
|
||||
categories: videos
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
- name: dogpile news
|
||||
engine: dogpile
|
||||
shortcut: dogn
|
||||
dogpile_categ: news
|
||||
categories: news
|
||||
disabled: true
|
||||
inactive: true
|
||||
|
||||
# duckduckgo uses html.duckduckgo.com,
|
||||
# duckduckgo web uses duckduckgo.com
|
||||
@@ -1411,6 +1410,12 @@ engines:
|
||||
shortcut: iq
|
||||
disabled: true
|
||||
|
||||
- name: jina
|
||||
engine: jina
|
||||
shortcut: ji
|
||||
api_key: ""
|
||||
inactive: true
|
||||
|
||||
# - name: kagi
|
||||
# engine: kagi
|
||||
# categories: [general, web]
|
||||
@@ -2579,6 +2584,16 @@ engines:
|
||||
shortcut: ydi
|
||||
disabled: true
|
||||
|
||||
- name: yandex api
|
||||
engine: yandex_api
|
||||
categories: [general, web]
|
||||
shortcut: yda
|
||||
inactive: true
|
||||
# api_key: ""
|
||||
# folder_id: ""
|
||||
# search_type: SEARCH_TYPE_COM
|
||||
# l10n: LOCALIZATION_EN
|
||||
|
||||
- name: yandex music
|
||||
engine: yandex_music
|
||||
network: yandex
|
||||
|
||||
@@ -192,7 +192,7 @@ SCHEMA: dict[str, t.Any] = {
|
||||
'brand': SettingsBrand,
|
||||
'search': {
|
||||
'safe_search': SettingsValue((0, 1, 2), 0),
|
||||
'autocomplete': SettingsValue(str, ''),
|
||||
'autocomplete': SettingsValue(str, 'duckduckgo'),
|
||||
'autocomplete_min': SettingsValue(int, 4),
|
||||
'favicon_resolver': SettingsValue(str, ''),
|
||||
'default_lang': SettingsValue(tuple(SXNG_LOCALE_TAGS + ['']), ''),
|
||||
@@ -219,7 +219,7 @@ SCHEMA: dict[str, t.Any] = {
|
||||
'base_url': SettingsValue((False, str), False, 'SEARXNG_BASE_URL'),
|
||||
'image_proxy': SettingsValue(bool, False, 'SEARXNG_IMAGE_PROXY'),
|
||||
'http_protocol_version': SettingsValue(('1.0', '1.1'), '1.0'),
|
||||
'method': SettingsValue(('POST', 'GET'), 'POST', 'SEARXNG_METHOD'),
|
||||
'method': SettingsValue(('POST', 'GET'), 'GET', 'SEARXNG_METHOD'),
|
||||
'default_http_headers': SettingsValue(dict, {}),
|
||||
},
|
||||
# redis is deprecated ..
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<div class="wrapper">
|
||||
{%- for output_type in search_formats -%}
|
||||
<div class="left">
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}">
|
||||
<input type="hidden" name="q" value="{{ q|e }}">
|
||||
{%- for category in selected_categories -%}
|
||||
<input type="hidden" name="category_{{ category }}" value="1">
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<h4 id="corrections-title">{{ _('Try searching for:') }}</h4>
|
||||
{% for correction in corrections %}
|
||||
<div class="left">
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" role="navigation">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}" role="navigation">
|
||||
{% for category in selected_categories %}
|
||||
<input type="hidden" name="category_{{ category }}" value="1">
|
||||
{% endfor %}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<div>
|
||||
<h3><bdi>{{ topic.name }}</bdi></h3>
|
||||
{%- for suggestion in topic.suggestions -%}
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}">
|
||||
<input type="hidden" name="q" value="{{ suggestion }}">
|
||||
<input type="hidden" name="time_range" value="{{ time_range }}">
|
||||
<input type="hidden" name="language" value="{{ current_language }}">
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<summary class="title" id="suggestions-title">{{ _('Suggestions') }}</summary>
|
||||
<ul class="wrapper">
|
||||
{%- for suggestion in suggestions -%}
|
||||
<li><form method="{{ method or 'POST' }}" action="{{ url_for('search') }}">
|
||||
<li><form method="{{ method }}" action="{{ url_for('search') }}">
|
||||
<input type="hidden" name="q" value="{{ suggestion.url }}">
|
||||
{%- for category in selected_categories -%}
|
||||
<input type="hidden" name="category_{{ category }}" value="1">
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
{% if paging %}
|
||||
<nav id="pagination" role="navigation">
|
||||
{% if pageno > 1 %}
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="previous_page">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}" class="previous_page">
|
||||
<div class="{% if rtl %}right{% else %}left{% endif %}">
|
||||
<input type="hidden" name="q" value="{{ q|e }}" >
|
||||
{% for category in selected_categories %}
|
||||
@@ -93,7 +93,7 @@
|
||||
</form>
|
||||
{% endif %}
|
||||
{%- if results | count > 0 -%}
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="next_page">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}" class="next_page">
|
||||
<div class="{% if rtl %}left{% else %}right{% endif %}">
|
||||
<input type="hidden" name="q" value="{{ q|e }}" >
|
||||
{% for category in selected_categories %}
|
||||
@@ -119,7 +119,7 @@
|
||||
|
||||
<div class="numbered_pagination">
|
||||
{% for x in range(pstart, pend) %}
|
||||
<form method="{{ method or 'POST' }}" action="{{ url_for('search') }}" class="page_number">
|
||||
<form method="{{ method }}" action="{{ url_for('search') }}" class="page_number">
|
||||
<input type="hidden" name="q" value="{{ q|e }}" >
|
||||
{% for category in selected_categories %}
|
||||
<input type="hidden" name="category_{{ category }}" value="1" >
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<form id="search" method="{{ method or 'POST' }}" action="{{ url_for('search') }}" role="search">
|
||||
<form id="search" method="{{ method }}" action="{{ url_for('search') }}" role="search">
|
||||
<div id="search_header">
|
||||
<a id="search_logo" href="{{ url_for('index') }}" tabindex="0" title="{{ _('Display the front page') }}">
|
||||
<span hidden>SearXNG</span>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<form id="search" method="{{ method or 'POST' }}" action="{{ url_for('search') }}" role="search">
|
||||
<form id="search" method="{{ method }}" action="{{ url_for('search') }}" role="search">
|
||||
<div id="search_header">
|
||||
<div id="search_view">
|
||||
<div class="search_box">
|
||||
|
||||
Binary file not shown.
@@ -25,21 +25,23 @@
|
||||
# return42 <return42@noreply.codeberg.org>, 2025, 2026.
|
||||
# ehsanrs2 <ehsanrs2@noreply.codeberg.org>, 2025.
|
||||
# Artiman <artiman@noreply.codeberg.org>, 2025.
|
||||
# mvtbh <mvtbh@noreply.codeberg.org>, 2026.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-15 15:45+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"PO-Revision-Date: 2026-08-04 12:25+0000\n"
|
||||
"Last-Translator: mvtbh <mvtbh@noreply.codeberg.org>\n"
|
||||
"Language: fa_IR\n"
|
||||
"Language-Team: Persian "
|
||||
"<https://translate.codeberg.org/projects/searxng/searxng/fa/>\n"
|
||||
"Language-Team: Persian <https://translate.codeberg.org/projects/searxng/"
|
||||
"searxng/fa/>\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
"X-Generator: Weblate 2026.7.1\n"
|
||||
|
||||
#. CONSTANT_NAMES['NO_SUBGROUPING']
|
||||
#: searx/searxng.msg
|
||||
@@ -449,47 +451,47 @@ msgstr ""
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Light snow"
|
||||
msgstr ""
|
||||
msgstr "برف خفیف"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow and thunder"
|
||||
msgstr ""
|
||||
msgstr "برف و رعد و برق"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow showers and thunder"
|
||||
msgstr ""
|
||||
msgstr "رگبار برف و رعد و برق"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow showers"
|
||||
msgstr ""
|
||||
msgstr "رگبار برف"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow"
|
||||
msgstr ""
|
||||
msgstr "برف"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Heavy snow and thunder"
|
||||
msgstr ""
|
||||
msgstr "برف سنگین و رعد و برق"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Heavy snow showers and thunder"
|
||||
msgstr ""
|
||||
msgstr "رگبار برف سنگین و رعد و برق"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Heavy snow showers"
|
||||
msgstr ""
|
||||
msgstr "رگبار شدید برف"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Heavy snow"
|
||||
msgstr ""
|
||||
msgstr "برف سنگین"
|
||||
|
||||
#. SOCIAL_MEDIA_TERMS['SUBSCRIBERS']
|
||||
#: searx/engines/lemmy.py:85 searx/searxng.msg
|
||||
@@ -2406,4 +2408,3 @@ msgstr "پنهانسازی ویدئو"
|
||||
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "موتور"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -11,18 +11,18 @@ msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-15 15:45+0000\n"
|
||||
"PO-Revision-Date: 2026-05-05 12:37+0000\n"
|
||||
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@noreply.codeberg.org>"
|
||||
"\n"
|
||||
"PO-Revision-Date: 2026-08-04 12:25+0000\n"
|
||||
"Last-Translator: Aindriú Mac Giolla Eoin <aindriu80@noreply.codeberg.org>\n"
|
||||
"Language: ga\n"
|
||||
"Language-Team: Irish "
|
||||
"<https://translate.codeberg.org/projects/searxng/searxng/ga/>\n"
|
||||
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 "
|
||||
":(n>6 && n<11) ? 3 : 4;\n"
|
||||
"Language-Team: Irish <https://translate.codeberg.org/projects/searxng/"
|
||||
"searxng/ga/>\n"
|
||||
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : n==2 ? 1 : (n>2 && n<7) ? 2 :(n>"
|
||||
"6 && n<11) ? 3 : 4;\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
"X-Generator: Weblate 2026.7.1\n"
|
||||
|
||||
#. CONSTANT_NAMES['NO_SUBGROUPING']
|
||||
#: searx/searxng.msg
|
||||
@@ -1646,11 +1646,11 @@ msgstr "Réiteach"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:55
|
||||
msgid "Image formats"
|
||||
msgstr ""
|
||||
msgstr "Formáidí íomhá"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:56
|
||||
msgid "original format"
|
||||
msgstr ""
|
||||
msgstr "formáid bhunaidh"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:64
|
||||
msgid "View source"
|
||||
@@ -1969,4 +1969,3 @@ msgstr "físeán a cheilt"
|
||||
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Inneall"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -24,22 +24,24 @@
|
||||
# ngf <ngf@noreply.codeberg.org>, 2025.
|
||||
# return42 <return42@noreply.codeberg.org>, 2025, 2026.
|
||||
# omeritzics <omeritzics@noreply.codeberg.org>, 2026.
|
||||
# ShinyDust <shinydust@noreply.codeberg.org>, 2026.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-07-15 15:45+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"PO-Revision-Date: 2026-08-02 00:25+0000\n"
|
||||
"Last-Translator: ShinyDust <shinydust@noreply.codeberg.org>\n"
|
||||
"Language: he\n"
|
||||
"Language-Team: Hebrew "
|
||||
"<https://translate.codeberg.org/projects/searxng/searxng/he/>\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 "
|
||||
"&& n % 10 == 0) ? 2 : 3));\n"
|
||||
"Language-Team: Hebrew <https://translate.codeberg.org/projects/searxng/"
|
||||
"searxng/he/>\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n == 1) ? 0 : ((n == 2) ? 1 : ((n > 10 && "
|
||||
"n % 10 == 0) ? 2 : 3));\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
"X-Generator: Weblate 2026.7.1\n"
|
||||
|
||||
#. CONSTANT_NAMES['NO_SUBGROUPING']
|
||||
#: searx/searxng.msg
|
||||
@@ -394,17 +396,17 @@ msgstr "שלג קל"
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Sleet and thunder"
|
||||
msgstr ""
|
||||
msgstr "שלג ורעמים"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Sleet showers and thunder"
|
||||
msgstr ""
|
||||
msgstr "ממטרי שלג ורעמים"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Sleet showers"
|
||||
msgstr ""
|
||||
msgstr "ממטרי שלג"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
@@ -444,7 +446,7 @@ msgstr "ממטרי שלג קלים ורעמים"
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Light snow showers"
|
||||
msgstr ""
|
||||
msgstr "ממטרי שלג קלים"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
@@ -454,17 +456,17 @@ msgstr "שלג קל"
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow and thunder"
|
||||
msgstr ""
|
||||
msgstr "שלג ורעמים"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow showers and thunder"
|
||||
msgstr ""
|
||||
msgstr "ממטרי שלג ורעמים"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Snow showers"
|
||||
msgstr ""
|
||||
msgstr "ממטרי שלג"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
@@ -655,7 +657,7 @@ msgstr "חשב {func} של הארגומנטים"
|
||||
#: searx/engines/boardreader.py:108
|
||||
#, python-brace-format
|
||||
msgid "Posted by {author}"
|
||||
msgstr ""
|
||||
msgstr "פורסם על ידי {author}"
|
||||
|
||||
#: searx/engines/openstreetmap.py:155
|
||||
msgid "Show route in map .."
|
||||
@@ -743,7 +745,7 @@ msgstr "מחשבון"
|
||||
|
||||
#: searx/plugins/calculator.py:26
|
||||
msgid "Parses and solves mathematical expressions."
|
||||
msgstr ""
|
||||
msgstr "מנתח ופותר ביטויים מתמטיים."
|
||||
|
||||
#: searx/plugins/hash_plugin.py:33
|
||||
msgid "Hash plugin"
|
||||
@@ -754,6 +756,8 @@ msgid ""
|
||||
"Converts strings to different hash digests. Available functions: md5, "
|
||||
"sha1, sha224, sha256, sha384, sha512."
|
||||
msgstr ""
|
||||
"ממיר מחרוזות ל- hash digests שונים. פונקציות זמינות: md5, sha1, sha224, "
|
||||
"sha256, sha384, sha512."
|
||||
|
||||
#: searx/plugins/hash_plugin.py:63
|
||||
msgid "hash digest"
|
||||
@@ -983,14 +987,15 @@ msgid ""
|
||||
"This is a preview of the settings used by the 'Search URL' you used to "
|
||||
"get here."
|
||||
msgstr ""
|
||||
"זוהי תצוגה מקדימה של ההגדרות ב- 'כתובת URL לחיפוש' בהן השתמשת כדי להגיע לכאן."
|
||||
|
||||
#: searx/templates/simple/preferences.html:158
|
||||
msgid "Press save to copy these preferences to your browser."
|
||||
msgstr ""
|
||||
msgstr "לחץ על שמור כדי להעתיק את ההעדפות הללו לדפדפן שלך."
|
||||
|
||||
#: searx/templates/simple/preferences.html:159
|
||||
msgid "Click here to view your browser preferences instead:"
|
||||
msgstr ""
|
||||
msgstr "לחץ כאן כדי להציג את העדפות הדפדפן שלך במקום:"
|
||||
|
||||
#: searx/templates/simple/preferences.html:169
|
||||
msgid "General"
|
||||
@@ -1333,7 +1338,7 @@ msgstr "השלמה אוטומטית"
|
||||
|
||||
#: searx/templates/simple/preferences/autocomplete.html:15
|
||||
msgid "Show possible queries as you type"
|
||||
msgstr ""
|
||||
msgstr "הצג שאילתות אפשריות תוך כדי הקלדה"
|
||||
|
||||
#: searx/templates/simple/preferences/center_alignment.html:2
|
||||
msgid "Center Alignment"
|
||||
@@ -1351,7 +1356,7 @@ msgstr "זוהי רשימת העוגיות וערכיהן אשר SearXNG מאח
|
||||
|
||||
#: searx/templates/simple/preferences/cookies.html:3
|
||||
msgid "With this list, you can assess the transparency of SearXNG."
|
||||
msgstr ""
|
||||
msgstr "בעזרת רשימה זו, תוכלו להעריך את השקיפות של SearXNG."
|
||||
|
||||
#: searx/templates/simple/preferences/cookies.html:9
|
||||
msgid "Cookie name"
|
||||
@@ -1642,11 +1647,11 @@ msgstr "רזולוציה"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:55
|
||||
msgid "Image formats"
|
||||
msgstr ""
|
||||
msgstr "פורמטי תמונה"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:56
|
||||
msgid "original format"
|
||||
msgstr ""
|
||||
msgstr "פורמט מקורי"
|
||||
|
||||
#: searx/templates/simple/result_templates/images.html:64
|
||||
msgid "View source"
|
||||
@@ -2373,4 +2378,3 @@ msgstr "הסתר וידאו"
|
||||
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "מנוע"
|
||||
|
||||
|
||||
@@ -1195,7 +1195,7 @@ def opensearch():
|
||||
method = 'GET'
|
||||
|
||||
if method not in ('POST', 'GET'):
|
||||
method = 'POST'
|
||||
method = 'GET'
|
||||
|
||||
ret = render('opensearch.xml', opensearch_method=method, autocomplete=autocomplete)
|
||||
resp = Response(response=ret, status=200, mimetype="application/opensearchdescription+xml")
|
||||
|
||||
Reference in New Issue
Block a user