From 799d72e3fd74fd0967a79f07bbf541ce7f0f3e84 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Mon, 19 Aug 2024 11:29:57 +0200 Subject: [PATCH 1/8] [mod] add French translation for infopage The French translation was provided by @jcarnat in #3738. [3738] https://github.com/searxng/searxng/issues/3738 Co-authored-by: Joel Carnat @jcarnat https://github.com/jcarnat Signed-off-by: Markus Heiser --- searx/infopage/fr/about.md | 87 +++++++++++++++++++++++++++ searx/infopage/fr/search-syntax.md | 97 ++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 searx/infopage/fr/about.md create mode 100644 searx/infopage/fr/search-syntax.md diff --git a/searx/infopage/fr/about.md b/searx/infopage/fr/about.md new file mode 100644 index 000000000..402f28069 --- /dev/null +++ b/searx/infopage/fr/about.md @@ -0,0 +1,87 @@ +# A propos de SearXNG + +SearXNG est un [Métamoteur] qui agrège les résultats d'autres +{{link('moteurs de recherche', 'preferences')}} tout en ne sauvegardant +aucune informations à propos de ses utilisateurs. + +Le projet SearXNG est maintenu par une communauté ouverte. +Rejoignez-nous sur Matrix si vous avez des questions ou simplement pour +discuter de SearXNG: [#searxng:matrix.org]. + +Aidez-nous à rendre SearXNG meilleur. + +- Vous pouvez améliorer les traductions de SearXNG avec l'outil + [Weblate]. +- Suivez le développement, contribuez au projet ou remontez des erreurs + en utilisant le [dépôt de sources]. +- Pour obtenir de plus amples informations, consultez la documentation + en ligne du [projet SearXNG]. + +## Pourquoi l'utiliser ? + +- SearXNG ne vous fournira pas de résultats aussi personnalisés que + Google, mais il ne générera pas non plus de suivi sur vous. +- SearXNG ne se soucis pas des recherches que vous faites, ne partage + aucune information avec des tiers et ne peut pas être utilisé contre + vous. +- SearXNG est un logiciel libre. Son code source est 100% ouvert et tout + le mode est encouragé à l'améliorer. + +Si vous êtes soucieux du respect de la vie privée et des libertés sur +Internet, faites de SearXNG votre moteur de recherche par défaut. Vous +pouvez aussi installer et utiliser SearXNG sur votre propre serveur. + +## Comment le configurer comme moteur de recherche par défaut ? + +SearXNG prend en charge [OpenSearch]. Pour plus d'informations sur la +manière de modifier votre moteur de recherche par défaut, veuillez +consulter la documentation de votre navigateur : + +- [Firefox] +- [Microsoft Edge] - Ce lien propose aussi les instructions pour les + navigateurs Chrome et Safari. +- Les navigateurs basés sur [Chromium] permettent d'ajouter des sites de + navigation sans même y accéder. + +Lorsqu'un moteur de recherche est ajouté, son nom doit être unique. Si +vous ne pouvez pas ajouter un moteur de recherche, veuillez : + +- Supprimer le doublon (le nom par défaut est SearXNG) ou bien +- Contacter le propriétaire de l'instance que vous souhaitez utiliser + afin qu'il modifie le nom de celle-ci. + +## Comment ça marche ? + +SearXNG est une reprise logicielle du projet [searx] [Métamoteur], +lui-même inspiré du [projet Seeks]. Il assure la confidentialité en +mélangeant vos recherches vers d'autres plateformes sans stocker aucune +données de recherche. SearXNG peut être ajouté à la barre de recherche +de votre navigateur et même être utilisé comme moteur de recherche par +défaut. + +Le lien "{{link('statistiques des moteurs', 'stats')}}" présente des +informations anonymisées concernant l'utilisation des divers moteurs de +recherche. + +## Comment reprendre la main ? + +SearXNG apprécie votre préoccupation concernant les traces de recherche. +N'hésitez pas à utiliser le [dépôt de sources] et à maintenir votre +propre instance de recherche. + +Ajouter votre instance à la [liste d'instances +publiques]({{get_setting('brand.public_instances')}}) afin d'aider +d'autres personnes à protéger leur vie privée et rendre l'Internet plus +libre. Plus Internet sera décentralisé, plus nous aurons de liberté ! + +[dépôt de sources]: {{GIT_URL}} +[#searxng:matrix.org]: https://matrix.to/#/#searxng:matrix.org +[projet SearXNG]: {{get_setting('brand.docs_url')}} +[searx]: https://github.com/searx/searx +[Métamoteur]: https://fr.wikipedia.org/wiki/M%C3%A9tamoteur +[Weblate]: https://translate.codeberg.org/projects/searxng/ +[projet Seeks]: https://beniz.github.io/seeks/ +[OpenSearch]: https://github.com/dewitt/opensearch/blob/master/opensearch-1-1-draft-6.md +[Firefox]: https://support.mozilla.org/en-US/kb/add-or-remove-search-engine-firefox +[Microsoft Edge]: https://support.microsoft.com/en-us/help/4028574/microsoft-edge-change-the-default-search-engine +[Chromium]: https://www.chromium.org/tab-to-search diff --git a/searx/infopage/fr/search-syntax.md b/searx/infopage/fr/search-syntax.md new file mode 100644 index 000000000..15e678bb3 --- /dev/null +++ b/searx/infopage/fr/search-syntax.md @@ -0,0 +1,97 @@ +# Syntaxe de recherche + +SearXNG permet de modifier les catégories de recherche, les moteurs +utilisés ou encore la langue de recherche par l'intermédiaire d'une +syntaxe dédiée. La liste des moteurs de recherche, de catégories et de +langues disponibles est accessible depuis la page de +{{link('préférences', 'preferences')}}. + +## `!` Spécifier un moteur ou une catégorie + +Pour restreindre la recherche à un moteur ou une catégorie, utilisez le +caractère "!". Voici quelques exemples d'utilisation : + +- Rechercher **paris** sur Wikipédia. + + - {{search('!wp paris')}} + - {{search('!wikipedia paris')}} + +- Rechercher **paris** dans la catégorie **Carte**. + + - {{search('!map paris')}} + +- Rechercher des **Images**. + + - {{search('!images Wau Holland')}} + +Les abréviations de moteurs et de langues sont aussi valides. Il est +possible d'accumuler les moteurs et catégories dans une requête +complexe. Par exemple, {{search('!map !ddg !wp paris')}} recherchera +**paris** dans la catégorie **Carte** de DuckDuckGo et Wikipédia. + +## `:` Spécifier une langue + +Utilisez le préfixe ":" pour limiter la recherche à une langue en +particulier. Par exemple : + +- Rechercher dans les pages françaises de Wikipédia. + + - {{search(':fr !wp Wau Holland')}} + +## `!!` Recherches externes (!Bang) + +SearXNG supporte les recherches [DuckDuckGo] de type "!Bang". Utilisez +le préfixe "!!" pour être automatiquement redirigé vers un moteur de +recherche externe. Par exemple : + +- Rechercher sur Wikipédia en langue française. + + - {{search('!!wfr Wau Holland')}} + +Prenez garde au fait que de telles recherches sont exécutées directement +sur le moteur externe. Dans ce cas, SearXNG ne peut pas protéger votre +vie privée. + +[DuckDuckGo]: https://duckduckgo.com/bang + +## `!!` Redirection automatique + +En utilisant "!!" suivi d'un ou plusieurs espaces lors de votre +recherche, vous serez automatiquement redirigé vers le premier résultat +de recherche. Cela correspondant au fonctionnement "J'ai de la chance" +du moteur Google. Par exemple : + +- Rechercher et être redirigé directement vers le premier lien + correspondant. + + - {{search('!! Wau Holland')}} + +Prenez garde au fait qu'aucune vérification ne peut être faite +concernant le premier lien retourné. Il pourrait même s'agir d'un site +dangereux. Dans ce cas, SearXNG ne peut pas protéger votre vie +privée. Soyez prudent en utilisant cette fonctionnalité. + +## Requêtes spéciales + +Dans la section _requêtes spéciales_ de la page de {{link('préférences', +'preferences')}} se trouve une liste de mots clés à usage particulier. +Par exemple : + +- Générer une valeur aléatoire. + + - {{search('random uuid')}} + +- Calculer une moyenne. + + - {{search('avg 123 548 2.04 24.2')}} + +- Afficher la valeur de la variable _User-Agent_ utilisée par votre + navigateur (doit être activé manuellement). + + - {{search('user-agent')}} + +- Convertir une chaîne de caractères en valeurs de hachage ("hash digests") + (doit être activé manuellement). + + - {{search('md5 lorem ipsum')}} + - {{search('sha512 lorem ipsum')}} From 5c6b126d7f2bbd12c6944247068b49ec3a9b7dee Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Tue, 20 Aug 2024 16:43:49 +0200 Subject: [PATCH 2/8] [fix] debian/ubuntu python-is-python3 Closes: https://github.com/searxng/searxng/issues/3235 Signed-off-by: Markus Heiser --- manage | 2 +- utils/lib.sh | 2 +- utils/lib_go.sh | 4 ++-- utils/searxng.sh | 10 +++------- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/manage b/manage index 155a1f2dd..2a88a4c5c 100755 --- a/manage +++ b/manage @@ -233,7 +233,7 @@ gecko.driver() { build_msg INSTALL "geckodriver already installed" return fi - PLATFORM="$(python3 -c 'import platform; print(platform.system().lower(), platform.architecture()[0])')" + PLATFORM="$(python -c 'import platform; print(platform.system().lower(), platform.architecture()[0])')" case "$PLATFORM" in "linux 32bit" | "linux2 32bit") ARCH="linux32";; "linux 64bit" | "linux2 64bit") ARCH="linux64";; diff --git a/utils/lib.sh b/utils/lib.sh index 16bfb4398..e527fa1b6 100755 --- a/utils/lib.sh +++ b/utils/lib.sh @@ -1674,7 +1674,7 @@ EOF } # apt packages -LXC_BASE_PACKAGES_debian="bash git build-essential python3 python3-venv" +LXC_BASE_PACKAGES_debian="bash git build-essential python3 python3-venv python-is-python3" # pacman packages LXC_BASE_PACKAGES_arch="bash git base-devel python" diff --git a/utils/lib_go.sh b/utils/lib_go.sh index 462bbbba0..0b58fad61 100755 --- a/utils/lib_go.sh +++ b/utils/lib_go.sh @@ -41,7 +41,7 @@ EOF } go.ls(){ - python3 <&1 | prefix_stdout "$_service_prefix" rm -rf "${SEARXNG_PYENV}" -python3 -m venv "${SEARXNG_PYENV}" +python -m venv "${SEARXNG_PYENV}" grep -qFs -- 'source ${SEARXNG_PYENV}/bin/activate' ~/.profile \ || echo 'source ${SEARXNG_PYENV}/bin/activate' >> ~/.profile EOF From 5be55e3309761842e070f48580a519499cfc8ceb Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Wed, 21 Aug 2024 08:19:54 +0200 Subject: [PATCH 3/8] [fix] unit tests: fix load / unload engines & fix messages - https://github.com/searxng/searxng/pull/3746#issuecomment-2300965005 - https://github.com/searxng/searxng/issues/2988#issuecomment-2226929084 Signed-off-by: Markus Heiser --- tests/unit/test_engines_init.py | 1 + tests/unit/test_search.py | 6 ++++++ tests/unit/test_webapp.py | 6 ++++++ 3 files changed, 13 insertions(+) diff --git a/tests/unit/test_engines_init.py b/tests/unit/test_engines_init.py index 4872a1b1b..e2445160a 100644 --- a/tests/unit/test_engines_init.py +++ b/tests/unit/test_engines_init.py @@ -10,6 +10,7 @@ class TestEnginesInit(SearxTestCase): # pylint: disable=missing-class-docstring def tearDownClass(cls): settings['outgoing']['using_tor_proxy'] = False settings['outgoing']['extra_proxy_timeout'] = 0 + engines.load_engines([]) def test_initialize_engines_default(self): engine_list = [ diff --git a/tests/unit/test_search.py b/tests/unit/test_search.py index b85c90c68..a60089aef 100644 --- a/tests/unit/test_search.py +++ b/tests/unit/test_search.py @@ -2,6 +2,7 @@ # pylint: disable=missing-module-docstring, invalid-name from copy import copy +import logging import searx.search from searx.search import SearchQuery, EngineRef @@ -46,8 +47,13 @@ class SearchQueryTestCase(SearxTestCase): # pylint: disable=missing-class-docst class SearchTestCase(SearxTestCase): # pylint: disable=missing-class-docstring def setUp(self): + log = logging.getLogger("searx") + log_lev = log.level + log.setLevel(logging.ERROR) from searx import webapp # pylint: disable=import-outside-toplevel + log.setLevel(log_lev) + self.app = webapp.app @classmethod diff --git a/tests/unit/test_webapp.py b/tests/unit/test_webapp.py index 868645e17..7c6e1ef82 100644 --- a/tests/unit/test_webapp.py +++ b/tests/unit/test_webapp.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # pylint: disable=missing-module-docstring +import logging import json from urllib.parse import ParseResult from mock import Mock @@ -20,8 +21,13 @@ class ViewsTestCase(SearxTestCase): # pylint: disable=missing-class-docstring, self.setattr4test(searx.search.processors, 'initialize_processor', dummy) + log = logging.getLogger("searx") + log_lev = log.level + log.setLevel(logging.ERROR) from searx import webapp # pylint: disable=import-outside-toplevel + log.setLevel(log_lev) + webapp.app.config['TESTING'] = True # to get better error messages self.app = webapp.app.test_client() From 5276219b9d790baeeb505813bb76d0dffa1d2d51 Mon Sep 17 00:00:00 2001 From: Grant Lanham Date: Mon, 19 Aug 2024 23:02:06 -0400 Subject: [PATCH 4/8] Fix tineye engine url, datetime parsing, and minor refactor Changes made to tineye engine: 1. Importing logging if TYPE_CHECKING is enabled 2. Remove unecessary try-catch around json parsing the response, as this masked the original error and had no immediate benefit 3. Improve error handling explicitely for status code 422 and 400 upfront, deferring json_parsing only for these status codes and successful status codes 4. Unit test all new applicable changes to ensure compatability --- searx/engines/tineye.py | 57 +++++++++++---------- tests/unit/test_tineye.py | 102 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 tests/unit/test_tineye.py diff --git a/searx/engines/tineye.py b/searx/engines/tineye.py index 196c89a2b..c35799c69 100644 --- a/searx/engines/tineye.py +++ b/searx/engines/tineye.py @@ -14,10 +14,16 @@ billion images `[tineye.com] `_. """ +from typing import TYPE_CHECKING from urllib.parse import urlencode from datetime import datetime from flask_babel import gettext +if TYPE_CHECKING: + import logging + + logger = logging.getLogger() + about = { "website": 'https://tineye.com', "wikidata_id": 'Q2382535', @@ -34,7 +40,7 @@ categories = ['general'] paging = True safesearch = False base_url = 'https://tineye.com' -search_string = '/result_json/?page={page}&{query}' +search_string = '/api/v1/result_json/?page={page}&{query}' FORMAT_NOT_SUPPORTED = gettext( "Could not read that image url. This may be due to an unsupported file" @@ -120,7 +126,7 @@ def parse_tineye_match(match_json): crawl_date = backlink_json.get("crawl_date") if crawl_date: - crawl_date = datetime.fromisoformat(crawl_date[:-3]) + crawl_date = datetime.strptime(crawl_date, '%Y-%m-%d') else: crawl_date = datetime.min @@ -150,29 +156,15 @@ def parse_tineye_match(match_json): def response(resp): """Parse HTTP response from TinEye.""" - results = [] - try: + # handle the 422 client side errors, and the possible 400 status code error + if resp.status_code in (400, 422): json_data = resp.json() - except Exception as exc: # pylint: disable=broad-except - msg = "can't parse JSON response // %s" % exc - logger.error(msg) - json_data = {'error': msg} - - # handle error codes from Tineye - - if resp.is_error: - if resp.status_code in (400, 422): - - message = 'HTTP status: %s' % resp.status_code - error = json_data.get('error') - s_key = json_data.get('suggestions', {}).get('key', '') - - if error and s_key: - message = "%s (%s)" % (error, s_key) - elif error: - message = error + suggestions = json_data.get('suggestions', {}) + message = f'HTTP Status Code: {resp.status_code}' + if resp.status_code == 422: + s_key = suggestions.get('key', '') if s_key == "Invalid image URL": # test https://docs.searxng.org/_static/searxng-wordmark.svg message = FORMAT_NOT_SUPPORTED @@ -182,16 +174,23 @@ def response(resp): elif s_key == 'Download Error': # test https://notexists message = DOWNLOAD_ERROR + else: + logger.warning("Unknown suggestion key encountered: %s", s_key) + else: # 400 + description = suggestions.get('description') + if isinstance(description, list): + message = ','.join(description) - # see https://github.com/searxng/searxng/pull/1456#issuecomment-1193105023 - # results.append({'answer': message}) - logger.error(message) + # see https://github.com/searxng/searxng/pull/1456#issuecomment-1193105023 + # results.append({'answer': message}) + logger.error(message) + return [] - return results + # Raise for all other responses + resp.raise_for_status() - resp.raise_for_status() - - # append results from matches + results = [] + json_data = resp.json() for match_json in json_data['matches']: diff --git a/tests/unit/test_tineye.py b/tests/unit/test_tineye.py new file mode 100644 index 000000000..0530b4c5e --- /dev/null +++ b/tests/unit/test_tineye.py @@ -0,0 +1,102 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +# pylint: disable=missing-module-docstring + + +from datetime import datetime +from unittest.mock import Mock +from requests import HTTPError +from searx.engines import load_engines, tineye +from tests import SearxTestCase + + +class TinEyeTests(SearxTestCase): # pylint: disable=missing-class-docstring + + def setUp(self): + load_engines([{'name': 'tineye', 'engine': 'tineye', 'shortcut': 'tin', 'timeout': 9.0, 'disabled': True}]) + + def tearDown(self): + load_engines([]) + + def test_status_code_raises(self): + response = Mock() + response.status_code = 401 + response.raise_for_status.side_effect = HTTPError() + self.assertRaises(HTTPError, lambda: tineye.response(response)) + + def test_returns_empty_list_for_422(self): + response = Mock() + response.json.return_value = {} + response.status_code = 422 + response.raise_for_status.side_effect = HTTPError() + with self.assertLogs(tineye.logger) as _dev_null: + results = tineye.response(response) + self.assertEqual(0, len(results)) + + def test_logs_format_for_422(self): + response = Mock() + response.json.return_value = {"suggestions": {"key": "Invalid image URL"}} + response.status_code = 422 + response.raise_for_status.side_effect = HTTPError() + + with self.assertLogs(tineye.logger) as assert_logs_context: + tineye.response(response) + self.assertIn(tineye.FORMAT_NOT_SUPPORTED, ','.join(assert_logs_context.output)) + + def test_logs_signature_for_422(self): + response = Mock() + response.json.return_value = {"suggestions": {"key": "NO_SIGNATURE_ERROR"}} + response.status_code = 422 + response.raise_for_status.side_effect = HTTPError() + + with self.assertLogs(tineye.logger) as assert_logs_context: + tineye.response(response) + self.assertIn(tineye.NO_SIGNATURE_ERROR, ','.join(assert_logs_context.output)) + + def test_logs_download_for_422(self): + response = Mock() + response.json.return_value = {"suggestions": {"key": "Download Error"}} + response.status_code = 422 + response.raise_for_status.side_effect = HTTPError() + + with self.assertLogs(tineye.logger) as assert_logs_context: + tineye.response(response) + self.assertIn(tineye.DOWNLOAD_ERROR, ','.join(assert_logs_context.output)) + + def test_empty_list_for_400(self): + response = Mock() + response.json.return_value = {} + response.status_code = 400 + response.raise_for_status.side_effect = HTTPError() + with self.assertLogs(tineye.logger) as _dev_null: + results = tineye.response(response) + self.assertEqual(0, len(results)) + + def test_logs_description_for_400(self): + description = 'There was a problem with that request. Error ID: ad5fc955-a934-43c1-8187-f9a61d301645' + response = Mock() + response.json.return_value = {"suggestions": {"description": [description], "title": "Oops! We're sorry!"}} + response.status_code = 400 + response.raise_for_status.side_effect = HTTPError() + + with self.assertLogs(tineye.logger) as assert_logs_context: + tineye.response(response) + self.assertIn(description, ','.join(assert_logs_context.output)) + + def test_crawl_date_parses(self): + date_str = '2020-05-25' + date = datetime.strptime(date_str, '%Y-%m-%d') + response = Mock() + response.json.return_value = { + 'matches': [ + { + 'backlinks': [ + { + 'crawl_date': date_str, + } + ] + } + ] + } + response.status_code = 200 + results = tineye.response(response) + self.assertEqual(date, results[0]['publishedDate']) From e45b771ffaeeb41a22fa17690b27be98b01d14cc Mon Sep 17 00:00:00 2001 From: Austin-Olacsi <138650713+Austin-Olacsi@users.noreply.github.com> Date: Sun, 11 Aug 2024 21:38:01 -0600 Subject: [PATCH 5/8] [feat] engine: implementation of yandex (web, images) It's set to inactive in settings.yml because of CAPTCHA. You need to remove that from the settings.yml to get in use. Closes: https://github.com/searxng/searxng/issues/961 --- searx/engines/yandex.py | 133 ++++++++++++++++++++++++++++++++++++++++ searx/settings.yml | 16 +++++ 2 files changed, 149 insertions(+) create mode 100644 searx/engines/yandex.py diff --git a/searx/engines/yandex.py b/searx/engines/yandex.py new file mode 100644 index 000000000..2c6984fdc --- /dev/null +++ b/searx/engines/yandex.py @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: AGPL-3.0-or-later +"""Yandex (Web, images)""" + +from json import loads +from urllib.parse import urlencode +from html import unescape +from lxml import html +from searx.exceptions import SearxEngineCaptchaException +from searx.utils import humanize_bytes, eval_xpath, eval_xpath_list, extract_text, extr + + +# Engine metadata +about = { + "website": 'https://yandex.com/', + "wikidata_id": 'Q5281', + "official_api_documentation": "?", + "use_official_api": False, + "require_api_key": False, + "results": 'HTML', +} + +# Engine configuration +categories = [] +paging = True +search_type = "" + +# Search URL +base_url_web = 'https://yandex.com/search/site/' +base_url_images = 'https://yandex.com/images/search' + +results_xpath = '//li[contains(@class, "serp-item")]' +url_xpath = './/a[@class="b-serp-item__title-link"]/@href' +title_xpath = './/h3[@class="b-serp-item__title"]/a[@class="b-serp-item__title-link"]/span' +content_xpath = './/div[@class="b-serp-item__content"]//div[@class="b-serp-item__text"]' + + +def catch_bad_response(resp): + if resp.url.path.startswith('/showcaptcha'): + raise SearxEngineCaptchaException() + + +def request(query, params): + query_params_web = { + "tmpl_version": "releases", + "text": query, + "web": "1", + "frame": "1", + "searchid": "3131712", + } + + query_params_images = { + "text": query, + "uinfo": "sw-1920-sh-1080-ww-1125-wh-999", + } + + if params['pageno'] > 1: + query_params_web.update({"p": params["pageno"] - 1}) + query_params_images.update({"p": params["pageno"] - 1}) + + params["cookies"] = {'cookie': "yp=1716337604.sp.family%3A0#1685406411.szm.1:1920x1080:1920x999"} + + if search_type == 'web': + params['url'] = f"{base_url_web}?{urlencode(query_params_web)}" + elif search_type == 'images': + params['url'] = f"{base_url_images}?{urlencode(query_params_images)}" + + return params + + +def response(resp): + if search_type == 'web': + + catch_bad_response(resp) + + dom = html.fromstring(resp.text) + + results = [] + + for result in eval_xpath_list(dom, results_xpath): + results.append( + { + 'url': extract_text(eval_xpath(result, url_xpath)), + 'title': extract_text(eval_xpath(result, title_xpath)), + 'content': extract_text(eval_xpath(result, content_xpath)), + } + ) + + return results + + if search_type == 'images': + + catch_bad_response(resp) + + html_data = html.fromstring(resp.text) + html_sample = unescape(html.tostring(html_data, encoding='unicode')) + + content_between_tags = extr( + html_sample, '{"location":"/images/search/', 'advRsyaSearchColumn":null}}', default="fail" + ) + json_data = '{"location":"/images/search/' + content_between_tags + 'advRsyaSearchColumn":null}}' + + if content_between_tags == "fail": + content_between_tags = extr(html_sample, '{"location":"/images/search/', 'false}}}') + json_data = '{"location":"/images/search/' + content_between_tags + 'false}}}' + + json_resp = loads(json_data) + + results = [] + for _, item_data in json_resp['initialState']['serpList']['items']['entities'].items(): + title = item_data['snippet']['title'] + source = item_data['snippet']['url'] + thumb = item_data['image'] + fullsize_image = item_data['viewerData']['dups'][0]['url'] + height = item_data['viewerData']['dups'][0]['h'] + width = item_data['viewerData']['dups'][0]['w'] + filesize = item_data['viewerData']['dups'][0]['fileSizeInBytes'] + humanized_filesize = humanize_bytes(filesize) + + results.append( + { + 'title': title, + 'url': source, + 'img_src': fullsize_image, + 'filesize': humanized_filesize, + 'thumbnail_src': thumb, + 'template': 'images.html', + 'resolution': f'{width} x {height}', + } + ) + + return results + + return [] diff --git a/searx/settings.yml b/searx/settings.yml index b3c7f5ffe..a1701d009 100644 --- a/searx/settings.yml +++ b/searx/settings.yml @@ -1814,6 +1814,22 @@ engines: engine: unsplash shortcut: us + - name: yandex + engine: yandex + categories: general + search_type: web + shortcut: yd + disabled: true + inactive: true + + - name: yandex images + engine: yandex + categories: images + search_type: images + shortcut: ydi + disabled: true + inactive: true + - name: yandex music engine: yandex_music shortcut: ydm From fe6bac5a08b8dfc8d91478f5ed78bd584ec9c147 Mon Sep 17 00:00:00 2001 From: Markus Heiser Date: Thu, 8 Aug 2024 11:46:54 +0200 Subject: [PATCH 6/8] [fix] pip install -e: legacy editable install (setup.py develop) is deprecated From [1]: There is now a standardized mechanism [2] for an installer like pip to request an editable install of a project. pip is transitioning to using this standard only instead of invoking the deprecated `setup.py develop` command. For backward compatibility, we can use switches: --use-pep517 https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-use-pep517 --no-build-isolation https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-no-build-isolation - [1] https://github.com/pypa/pip/issues/11457 - [2] https://peps.python.org/pep-0660/ Closes: https://github.com/searxng/searxng/issues/3701 Signed-off-by: Markus Heiser --- docs/build-templates/searxng.rst | 2 +- docs/dev/makefile.rst | 4 ++-- manage | 4 ++-- utils/lib.sh | 4 ++-- utils/searxng.sh | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/build-templates/searxng.rst b/docs/build-templates/searxng.rst index 14b385468..bc5d3e8fc 100644 --- a/docs/build-templates/searxng.rst +++ b/docs/build-templates/searxng.rst @@ -123,7 +123,7 @@ ${fedora_build} # jump to SearXNG's working tree and install SearXNG into virtualenv (${SERVICE_USER})$ cd \"$SEARXNG_SRC\" - (${SERVICE_USER})$ pip install -e . + (${SERVICE_USER})$ pip install --use-pep517 --no-build-isolation -e . .. END manage.sh update_packages diff --git a/docs/dev/makefile.rst b/docs/dev/makefile.rst index 3c3b2bf3b..383113bae 100644 --- a/docs/dev/makefile.rst +++ b/docs/dev/makefile.rst @@ -61,7 +61,7 @@ working tree and release a ``make install`` to get a virtualenv with a $ make install PYENV [virtualenv] installing ./requirements*.txt into local/py3 ... - PYENV [install] pip install -e 'searx[test]' + PYENV [install] pip install --use-pep517 --no-build-isolation -e 'searx[test]' ... Successfully installed searxng-2023.7.19+a446dea1b @@ -78,7 +78,7 @@ the check fails if you edit the requirements listed in ... PYENV [virtualenv] installing ./requirements*.txt into local/py3 ... - PYENV [install] pip install -e 'searx[test]' + PYENV [install] pip install --use-pep517 --no-build-isolation -e 'searx[test]' ... Successfully installed searxng-2023.7.19+a446dea1b diff --git a/manage b/manage index 2a88a4c5c..7edcb1f5a 100755 --- a/manage +++ b/manage @@ -299,8 +299,8 @@ pyenv.install() { ( set -e pyenv - build_msg PYENV "[install] pip install -e 'searx${PY_SETUP_EXTRAS}'" - "${PY_ENV_BIN}/python" -m pip install -e ".${PY_SETUP_EXTRAS}" + build_msg PYENV "[install] pip install --use-pep517 --no-build-isolation -e 'searx${PY_SETUP_EXTRAS}'" + "${PY_ENV_BIN}/python" -m pip install --use-pep517 --no-build-isolation -e ".${PY_SETUP_EXTRAS}" ) local exit_val=$? if [ ! $exit_val -eq 0 ]; then diff --git a/utils/lib.sh b/utils/lib.sh index e527fa1b6..b932b875c 100755 --- a/utils/lib.sh +++ b/utils/lib.sh @@ -663,8 +663,8 @@ pyenv.install() { pyenv fi for i in ${PYOBJECTS}; do - build_msg PYENV "[install] pip install -e '$i${PY_SETUP_EXTRAS}'" - "${PY_ENV_BIN}/python" -m pip install -e "$i${PY_SETUP_EXTRAS}" + build_msg PYENV "[install] pip install --use-pep517 --no-build-isolation -e '$i${PY_SETUP_EXTRAS}'" + "${PY_ENV_BIN}/python" -m pip install --use-pep517 --no-build-isolation -e "$i${PY_SETUP_EXTRAS}" done fi pyenv.install.OK diff --git a/utils/searxng.sh b/utils/searxng.sh index ea6a467d2..c15c18218 100755 --- a/utils/searxng.sh +++ b/utils/searxng.sh @@ -501,7 +501,7 @@ pip install -U setuptools pip install -U wheel pip install -U pyyaml cd ${SEARXNG_SRC} -pip install -e . +pip install --use-pep517 --no-build-isolation -e . EOF } @@ -569,7 +569,7 @@ pip install -U pip pip install -U setuptools pip install -U wheel pip install -U pyyaml -pip install -U -e . +pip install -U --use-pep517 --no-build-isolation -e . EOF rst_para "update instance's settings.yml from ${SEARXNG_SETTINGS_PATH}" DEFAULT_SELECT=2 \ From 2033f30c8df9e6af23876345785ec28ba982d5e5 Mon Sep 17 00:00:00 2001 From: Dennis ten Hoove Date: Fri, 16 Aug 2024 05:14:25 +0200 Subject: [PATCH 7/8] [docs] improve Hostname plugin documentation --- searx/plugins/hostnames.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/searx/plugins/hostnames.py b/searx/plugins/hostnames.py index 770b00e15..6519452db 100644 --- a/searx/plugins/hostnames.py +++ b/searx/plugins/hostnames.py @@ -1,7 +1,19 @@ # SPDX-License-Identifier: AGPL-3.0-or-later # pylint: disable=too-many-branches -"""In addition to rewriting/replace reslut URLs, the *hoostnames* plugin offers -other features. +""" +.. attention:: + + The **"Hostname replace"** plugin has been replace by **"Hostnames + plugin"**, see :pull:`3463` & :pull:`3552`. + +The **Hostnames plugin** can be enabled by adding it to the +``enabled_plugins`` **list** in the ``setting.yml`` like so. + + .. code:: yaml + + enabled_plugins: + - 'Hostnames plugin' + ... - ``hostnames.replace``: A **mapping** of regular expressions to hostnames to be replaced by other hostnames. From 4f7dd05d99f159111db152f86a583a5e2964d4a4 Mon Sep 17 00:00:00 2001 From: searxng-bot Date: Fri, 23 Aug 2024 07:09:56 +0000 Subject: [PATCH 8/8] [l10n] update translations from Weblate 1b63de5ca - 2024-08-21 - ghose 7c738125f - 2024-08-20 - crnobog --- searx/translations/gl/LC_MESSAGES/messages.mo | Bin 20555 -> 20555 bytes searx/translations/gl/LC_MESSAGES/messages.po | 14 ++--- searx/translations/sr/LC_MESSAGES/messages.mo | Bin 23984 -> 24310 bytes searx/translations/sr/LC_MESSAGES/messages.po | 48 ++++++++++-------- 4 files changed, 33 insertions(+), 29 deletions(-) diff --git a/searx/translations/gl/LC_MESSAGES/messages.mo b/searx/translations/gl/LC_MESSAGES/messages.mo index 3fa7e52993f5b5b55a76618e1c090ad37dc55964..b413d207ce9b037a596487a75f71e928d114f5ed 100644 GIT binary patch delta 29 lcmX@TfbsMK#tq^I>=wF4MhXU|o8=7V@-t>`-ecb{005M#35fsz delta 29 lcmX@TfbsMK#tq^I?B=@01_}lio8=7V@-wDx-ecb{005Mi35Eaw diff --git a/searx/translations/gl/LC_MESSAGES/messages.po b/searx/translations/gl/LC_MESSAGES/messages.po index 0f26c69a8..305186744 100644 --- a/searx/translations/gl/LC_MESSAGES/messages.po +++ b/searx/translations/gl/LC_MESSAGES/messages.po @@ -11,18 +11,19 @@ # return42 , 2024. msgid "" msgstr "" -"Project-Id-Version: searx\n" +"Project-Id-Version: searx\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-08-08 10:01+0000\n" -"PO-Revision-Date: 2024-07-30 08:18+0000\n" +"PO-Revision-Date: 2024-08-22 05:18+0000\n" "Last-Translator: ghose \n" +"Language-Team: Galician \n" "Language: gl\n" -"Language-Team: Galician " -"\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" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" "Generated-By: Babel 2.15.0\n" #. CONSTANT_NAMES['NO_SUBGROUPING'] @@ -1308,7 +1309,7 @@ msgid "" "multiple categories" msgstr "" "Buscar inmediatamente se hai unha categoría seleccionada. Desactiva para " -"elexir varias categorías" +"elixir varias categorías" #: searx/templates/simple/preferences/theme.html:2 msgid "Theme" @@ -1953,4 +1954,3 @@ msgstr "agochar vídeo" #~ msgid "Hostname replace" #~ msgstr "Substituír servidor" - diff --git a/searx/translations/sr/LC_MESSAGES/messages.mo b/searx/translations/sr/LC_MESSAGES/messages.mo index e9d4ddf5f7ddbb1d7c8a21938d4a07c338185393..64dff52189004d4d19bd4dbc8a63c57e4aa63d8a 100644 GIT binary patch delta 5204 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 delta 4894 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, 2022, 2023. # return42 , 2023. # return42 , 2024. +# crnobog , 2024. msgid "" msgstr "" -"Project-Id-Version: searx\n" +"Project-Id-Version: searx\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "POT-Creation-Date: 2024-08-08 10:01+0000\n" -"PO-Revision-Date: 2024-04-18 13:18+0000\n" -"Last-Translator: return42 " -"\n" +"PO-Revision-Date: 2024-08-21 01:18+0000\n" +"Last-Translator: crnobog \n" +"Language-Team: Serbian \n" "Language: sr\n" -"Language-Team: Serbian " -"\n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " -"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.6.2\n" "Generated-By: Babel 2.15.0\n" #. CONSTANT_NAMES['NO_SUBGROUPING'] @@ -76,7 +77,7 @@ msgstr "радио" #. CATEGORY_NAMES['TV'] #: searx/searxng.msg msgid "tv" -msgstr "" +msgstr "телевизија" #. CATEGORY_NAMES['IT'] #: searx/searxng.msg @@ -176,62 +177,66 @@ msgstr "О нама" #. WEATHER_TERMS['AVERAGE TEMP.'] #: searx/searxng.msg msgid "Average temp." -msgstr "" +msgstr "Просечна температура" #. WEATHER_TERMS['CLOUD COVER'] #: searx/searxng.msg msgid "Cloud cover" -msgstr "" +msgstr "Облачност" #. WEATHER_TERMS['CONDITION'] #: searx/searxng.msg msgid "Condition" -msgstr "" +msgstr "Стање" #. WEATHER_TERMS['CURRENT CONDITION'] #: searx/searxng.msg msgid "Current condition" -msgstr "" +msgstr "Тренутно стање" #. WEATHER_TERMS['EVENING'] #: searx/engines/wttr.py:100 searx/searxng.msg +#, fuzzy msgid "Evening" -msgstr "Vece" +msgstr "Вече" #. WEATHER_TERMS['FEELS LIKE'] #: searx/searxng.msg msgid "Feels like" -msgstr "" +msgstr "Осећај" #. WEATHER_TERMS['HUMIDITY'] #: searx/searxng.msg msgid "Humidity" -msgstr "" +msgstr "Влажност" #. WEATHER_TERMS['MAX TEMP.'] #: searx/searxng.msg msgid "Max temp." -msgstr "" +msgstr "Највећа темп." #. WEATHER_TERMS['MIN TEMP.'] #: searx/searxng.msg msgid "Min temp." -msgstr "" +msgstr "Најмања темп." #. WEATHER_TERMS['MORNING'] #: searx/engines/wttr.py:100 searx/searxng.msg +#, fuzzy msgid "Morning" -msgstr "Jutro" +msgstr "Јутро" #. WEATHER_TERMS['NIGHT'] #: searx/engines/wttr.py:100 searx/searxng.msg +#, fuzzy msgid "Night" -msgstr "Noc" +msgstr "Ноћ" #. WEATHER_TERMS['NOON'] #: searx/engines/wttr.py:100 searx/searxng.msg +#, fuzzy msgid "Noon" -msgstr "Podne" +msgstr "Подне" #. WEATHER_TERMS['PRESSURE'] #: searx/searxng.msg @@ -1934,4 +1939,3 @@ msgstr "сакриј видео" #~ msgid "Hostname replace" #~ msgstr "Замени име хостинга" -