mirror of
				https://github.com/searxng/searxng
				synced 2024-01-01 19:24:07 +01:00 
			
		
		
		
	Merge branch 'searxng:master' into master
This commit is contained in:
		
						commit
						1aca24f461
					
				
					 20 changed files with 539 additions and 80 deletions
				
			
		| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										6
									
								
								manage
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								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";;
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,10 +14,16 @@ billion images `[tineye.com] <https://tineye.com/how>`_.
 | 
			
		|||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
        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:
 | 
			
		||||
    # handle the 422 client side errors, and the possible 400 status code error
 | 
			
		||||
    if resp.status_code in (400, 422):
 | 
			
		||||
        json_data = resp.json()
 | 
			
		||||
        suggestions = json_data.get('suggestions', {})
 | 
			
		||||
        message = f'HTTP Status Code: {resp.status_code}'
 | 
			
		||||
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
        return []
 | 
			
		||||
 | 
			
		||||
            return results
 | 
			
		||||
 | 
			
		||||
    # Raise for all other responses
 | 
			
		||||
    resp.raise_for_status()
 | 
			
		||||
 | 
			
		||||
    # append results from matches
 | 
			
		||||
    results = []
 | 
			
		||||
    json_data = resp.json()
 | 
			
		||||
 | 
			
		||||
    for match_json in json_data['matches']:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										133
									
								
								searx/engines/yandex.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								searx/engines/yandex.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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 []
 | 
			
		||||
							
								
								
									
										87
									
								
								searx/infopage/fr/about.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								searx/infopage/fr/about.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
							
								
								
									
										97
									
								
								searx/infopage/fr/search-syntax.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								searx/infopage/fr/search-syntax.md
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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')}}
 | 
			
		||||
 | 
			
		||||
## `!!<bang>` 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')}}
 | 
			
		||||
| 
						 | 
				
			
			@ -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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1852,6 +1852,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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -14,15 +14,16 @@ msgstr ""
 | 
			
		|||
"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 <ghose@users.noreply.translate.codeberg.org>\n"
 | 
			
		||||
"Language-Team: Galician <https://translate.codeberg.org/projects/searxng/"
 | 
			
		||||
"searxng/gl/>\n"
 | 
			
		||||
"Language: gl\n"
 | 
			
		||||
"Language-Team: Galician "
 | 
			
		||||
"<https://translate.codeberg.org/projects/searxng/searxng/gl/>\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"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											Binary file not shown.
										
									
								
							| 
						 | 
				
			
			@ -10,22 +10,23 @@
 | 
			
		|||
# SecularSteve <fairfull.playing@gmail.com>, 2022, 2023.
 | 
			
		||||
# return42 <markus.heiser@darmarit.de>, 2023.
 | 
			
		||||
# return42 <return42@users.noreply.translate.codeberg.org>, 2024.
 | 
			
		||||
# crnobog <crnobog@users.noreply.translate.codeberg.org>, 2024.
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"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 <return42@users.noreply.translate.codeberg.org>"
 | 
			
		||||
"\n"
 | 
			
		||||
"PO-Revision-Date: 2024-08-21 01:18+0000\n"
 | 
			
		||||
"Last-Translator: crnobog <crnobog@users.noreply.translate.codeberg.org>\n"
 | 
			
		||||
"Language-Team: Serbian <https://translate.codeberg.org/projects/searxng/"
 | 
			
		||||
"searxng/sr/>\n"
 | 
			
		||||
"Language: sr\n"
 | 
			
		||||
"Language-Team: Serbian "
 | 
			
		||||
"<https://translate.codeberg.org/projects/searxng/searxng/sr/>\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 "Замени име хостинга"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 = [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										102
									
								
								tests/unit/test_tineye.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								tests/unit/test_tineye.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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'])
 | 
			
		||||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,7 +41,7 @@ EOF
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
go.ls(){
 | 
			
		||||
    python3 <<EOF
 | 
			
		||||
    python <<EOF
 | 
			
		||||
import sys, json, requests
 | 
			
		||||
resp = requests.get("${GO_DL_URL}/?mode=json&include=all")
 | 
			
		||||
for ver in json.loads(resp.text):
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ go.ver_info(){
 | 
			
		|||
    # os:    [darwin|freebsd|linux|windows]
 | 
			
		||||
    # arch:  [amd64|arm64|386|armv6l|ppc64le|s390x]
 | 
			
		||||
 | 
			
		||||
    python3 - "$@" <<EOF
 | 
			
		||||
    python - "$@" <<EOF
 | 
			
		||||
import sys, json, requests
 | 
			
		||||
resp = requests.get("${GO_DL_URL}/?mode=json&include=all")
 | 
			
		||||
for ver in json.loads(resp.text):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,13 +96,8 @@ case $DIST_ID-$DIST_VERS in
 | 
			
		|||
        SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
 | 
			
		||||
        APACHE_PACKAGES="$APACHE_PACKAGES libapache2-mod-proxy-uwsgi"
 | 
			
		||||
        ;;
 | 
			
		||||
    ubuntu-20.04)
 | 
			
		||||
        # https://wiki.ubuntu.com/FocalFossa/ReleaseNotes#Python3_by_default
 | 
			
		||||
        SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian} python-is-python3"
 | 
			
		||||
        SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
 | 
			
		||||
        ;;
 | 
			
		||||
    ubuntu-*|debian-*)
 | 
			
		||||
        SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian}"
 | 
			
		||||
        SEARXNG_PACKAGES="${SEARXNG_PACKAGES_debian} python-is-python3"
 | 
			
		||||
        SEARXNG_BUILD_PACKAGES="${SEARXNG_BUILD_PACKAGES_debian}"
 | 
			
		||||
        ;;
 | 
			
		||||
    arch-*)
 | 
			
		||||
| 
						 | 
				
			
			@ -453,6 +448,7 @@ searxng.install.clone() {
 | 
			
		|||
 | 
			
		||||
    # clone repo and add a safe.directory entry to git's system config / see
 | 
			
		||||
    # https://github.com/searxng/searxng/issues/1251
 | 
			
		||||
    git config --system --add safe.directory "${REPO_ROOT}/.git"
 | 
			
		||||
    git_clone "$REPO_ROOT" "${SEARXNG_SRC}" \
 | 
			
		||||
              "$GIT_BRANCH" "${SERVICE_USER}"
 | 
			
		||||
    git config --system --add safe.directory "${SEARXNG_SRC}"
 | 
			
		||||
| 
						 | 
				
			
			@ -489,7 +485,7 @@ searxng.install.pyenv() {
 | 
			
		|||
    info_msg "create pyenv in ${SEARXNG_PYENV}"
 | 
			
		||||
    tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&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
 | 
			
		||||
| 
						 | 
				
			
			@ -505,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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -573,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 \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue