Copy disabled (too large)
Download .txt
Showing preview only (13,905K chars total). Download the full file to get everything.
Repository: tiekoetter/searxng
Branch: master
Commit: f3d32c069702
Files: 905
Total size: 12.5 MB
Directory structure:
gitextract_vt94lyrq/
├── .coveragerc
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .dir-locals-template.el
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ ├── config.yml
│ │ ├── engine-request.md
│ │ └── feature-request.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── container.yml
│ ├── data-update.yml
│ ├── documentation.yml
│ ├── integration.yml
│ ├── l10n.yml
│ └── security.yml
├── .gitignore
├── .nvmrc
├── .pylintrc
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .weblate
├── .yamllint.yml
├── AI_POLICY.rst
├── AUTHORS.rst
├── CHANGELOG.rst
├── CONTRIBUTING.rst
├── LICENSE
├── Makefile
├── PULL_REQUEST_TEMPLATE.md
├── README.rst
├── SECURITY.md
├── babel.cfg
├── client/
│ └── simple/
│ ├── .gitignore
│ ├── .stylelintrc.json
│ ├── README.rst
│ ├── biome.json
│ ├── generated/
│ │ └── pygments.less
│ ├── package.json
│ ├── src/
│ │ ├── js/
│ │ │ ├── Plugin.ts
│ │ │ ├── index.ts
│ │ │ ├── loader.ts
│ │ │ ├── main/
│ │ │ │ ├── autocomplete.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── preferences.ts
│ │ │ │ ├── results.ts
│ │ │ │ └── search.ts
│ │ │ ├── plugin/
│ │ │ │ ├── Calculator.ts
│ │ │ │ ├── InfiniteScroll.ts
│ │ │ │ └── MapView.ts
│ │ │ ├── router.ts
│ │ │ ├── toolkit.ts
│ │ │ └── util/
│ │ │ ├── appendAnswerElement.ts
│ │ │ ├── assertElement.ts
│ │ │ └── getElement.ts
│ │ └── less/
│ │ ├── animations.less
│ │ ├── autocomplete.less
│ │ ├── definitions.less
│ │ ├── detail.less
│ │ ├── embedded.less
│ │ ├── index.less
│ │ ├── info.less
│ │ ├── mixins.less
│ │ ├── preferences.less
│ │ ├── result_templates.less
│ │ ├── result_types/
│ │ │ ├── code.less
│ │ │ ├── file.less
│ │ │ ├── keyvalue.less
│ │ │ └── paper.less
│ │ ├── rss.less
│ │ ├── search.less
│ │ ├── stats.less
│ │ ├── style-center.less
│ │ ├── style-ltr.less
│ │ ├── style-rtl.less
│ │ ├── style.less
│ │ ├── toolkit.less
│ │ ├── toolkit_loader.less
│ │ └── weather.less
│ ├── theme_icons.ts
│ ├── tools/
│ │ ├── img.ts
│ │ ├── jinja_svg_catalog.html.edge
│ │ ├── jinja_svg_catalog.ts
│ │ └── plg.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── container/
│ ├── builder.dockerfile
│ ├── dist.dockerfile
│ ├── docker-compose.yml
│ └── entrypoint.sh
├── docs/
│ ├── _static/
│ │ └── searxng.css
│ ├── admin/
│ │ ├── answer-captcha.rst
│ │ ├── api.rst
│ │ ├── arch_public.dot
│ │ ├── architecture.rst
│ │ ├── buildhosts.rst
│ │ ├── index.rst
│ │ ├── installation-apache.rst
│ │ ├── installation-docker.rst
│ │ ├── installation-granian.rst
│ │ ├── installation-nginx.rst
│ │ ├── installation-scripts.rst
│ │ ├── installation-searxng.rst
│ │ ├── installation-uwsgi.rst
│ │ ├── installation.rst
│ │ ├── plugins.rst
│ │ ├── searx.favicons.rst
│ │ ├── searx.limiter.rst
│ │ ├── settings/
│ │ │ ├── index.rst
│ │ │ ├── settings.rst
│ │ │ ├── settings_brand.rst
│ │ │ ├── settings_categories_as_tabs.rst
│ │ │ ├── settings_engines.rst
│ │ │ ├── settings_general.rst
│ │ │ ├── settings_outgoing.rst
│ │ │ ├── settings_plugins.rst
│ │ │ ├── settings_redis.rst
│ │ │ ├── settings_search.rst
│ │ │ ├── settings_server.rst
│ │ │ ├── settings_ui.rst
│ │ │ └── settings_valkey.rst
│ │ └── update-searxng.rst
│ ├── build-templates/
│ │ └── searxng.rst
│ ├── conf.py
│ ├── dev/
│ │ ├── answerers/
│ │ │ ├── builtins.rst
│ │ │ ├── development.rst
│ │ │ ├── index.rst
│ │ │ ├── random.rst
│ │ │ └── statistics.rst
│ │ ├── commits.rst
│ │ ├── contribution_guide.rst
│ │ ├── csv_table.txt
│ │ ├── engines/
│ │ │ ├── demo/
│ │ │ │ ├── demo_offline.rst
│ │ │ │ └── demo_online.rst
│ │ │ ├── engine_overview.rst
│ │ │ ├── enginelib.rst
│ │ │ ├── engines.rst
│ │ │ ├── index.rst
│ │ │ ├── json_engine.rst
│ │ │ ├── mediawiki.rst
│ │ │ ├── offline/
│ │ │ │ ├── command-line-engines.rst
│ │ │ │ ├── nosql-engines.rst
│ │ │ │ ├── search-indexer-engines.rst
│ │ │ │ └── sql-engines.rst
│ │ │ ├── offline_concept.rst
│ │ │ ├── online/
│ │ │ │ ├── adobe_stock.rst
│ │ │ │ ├── alpinelinux.rst
│ │ │ │ ├── annas_archive.rst
│ │ │ │ ├── aol.rst
│ │ │ │ ├── archlinux.rst
│ │ │ │ ├── arxiv.rst
│ │ │ │ ├── astrophysics_data_system.rst
│ │ │ │ ├── azure.rst
│ │ │ │ ├── bing.rst
│ │ │ │ ├── bpb.rst
│ │ │ │ ├── brave.rst
│ │ │ │ ├── bt4g.rst
│ │ │ │ ├── cara.rst
│ │ │ │ ├── chinaso.rst
│ │ │ │ ├── core.rst
│ │ │ │ ├── crossref.rst
│ │ │ │ ├── dailymotion.rst
│ │ │ │ ├── discourse.rst
│ │ │ │ ├── duckduckgo.rst
│ │ │ │ ├── geizhals.rst
│ │ │ │ ├── gitea.rst
│ │ │ │ ├── github_code.rst
│ │ │ │ ├── gitlab.rst
│ │ │ │ ├── google.rst
│ │ │ │ ├── huggingface.rst
│ │ │ │ ├── karmasearch.rst
│ │ │ │ ├── lemmy.rst
│ │ │ │ ├── loc.rst
│ │ │ │ ├── marginalia.rst
│ │ │ │ ├── mastodon.rst
│ │ │ │ ├── moviepilot.rst
│ │ │ │ ├── mrs.rst
│ │ │ │ ├── mwmbl.rst
│ │ │ │ ├── odysee.rst
│ │ │ │ ├── openalex.rst
│ │ │ │ ├── openlibrary.rst
│ │ │ │ ├── peertube.rst
│ │ │ │ ├── piped.rst
│ │ │ │ ├── presearch.rst
│ │ │ │ ├── pubmed.rst
│ │ │ │ ├── qwant.rst
│ │ │ │ ├── radio_browser.rst
│ │ │ │ ├── recoll.rst
│ │ │ │ ├── repology.rst
│ │ │ │ ├── reuters.rst
│ │ │ │ ├── semantic_scholar.rst
│ │ │ │ ├── soundcloud.rst
│ │ │ │ ├── sourcehut.rst
│ │ │ │ ├── springer.rst
│ │ │ │ ├── startpage.rst
│ │ │ │ ├── tagesschau.rst
│ │ │ │ ├── torznab.rst
│ │ │ │ ├── tubearchivist.rst
│ │ │ │ ├── void.rst
│ │ │ │ ├── wallhaven.rst
│ │ │ │ ├── wikipedia.rst
│ │ │ │ ├── yacy.rst
│ │ │ │ ├── yahoo.rst
│ │ │ │ └── zlibrary.rst
│ │ │ ├── online_url_search/
│ │ │ │ └── tineye.rst
│ │ │ └── xpath.rst
│ │ ├── extended_types.rst
│ │ ├── hello.dot
│ │ ├── index.rst
│ │ ├── makefile.rst
│ │ ├── plugins/
│ │ │ ├── builtins.rst
│ │ │ ├── calculator.rst
│ │ │ ├── development.rst
│ │ │ ├── hash_plugin.rst
│ │ │ ├── hostnames.rst
│ │ │ ├── index.rst
│ │ │ ├── infinite_scroll.rst
│ │ │ ├── self_info.rst
│ │ │ ├── time_zone.rst
│ │ │ ├── tor_check.rst
│ │ │ └── unit_converter.rst
│ │ ├── quickstart.rst
│ │ ├── reST.rst
│ │ ├── result_types/
│ │ │ ├── answer.rst
│ │ │ ├── base_result.rst
│ │ │ ├── correction.rst
│ │ │ ├── index.rst
│ │ │ ├── infobox.rst
│ │ │ ├── main/
│ │ │ │ ├── code.rst
│ │ │ │ ├── file.rst
│ │ │ │ ├── keyvalue.rst
│ │ │ │ ├── mainresult.rst
│ │ │ │ └── paper.rst
│ │ │ ├── main_result.rst
│ │ │ └── suggestion.rst
│ │ ├── search_api.rst
│ │ ├── searxng_extra/
│ │ │ ├── index.rst
│ │ │ └── update.rst
│ │ ├── templates.rst
│ │ └── translation.rst
│ ├── index.rst
│ ├── own-instance.rst
│ ├── src/
│ │ ├── index.rst
│ │ ├── searx.babel_extract.rst
│ │ ├── searx.botdetection.rst
│ │ ├── searx.cache.rst
│ │ ├── searx.exceptions.rst
│ │ ├── searx.favicons.rst
│ │ ├── searx.infopage.rst
│ │ ├── searx.locales.rst
│ │ ├── searx.search.processors.rst
│ │ ├── searx.search.rst
│ │ ├── searx.settings.rst
│ │ ├── searx.sqlitedb.rst
│ │ ├── searx.utils.rst
│ │ ├── searx.valkeydb.rst
│ │ ├── searx.valkeylib.rst
│ │ └── searx.weather.rst
│ ├── user/
│ │ ├── .gitignore
│ │ ├── about.rst
│ │ ├── configured_engines.rst
│ │ ├── index.rst
│ │ └── search-syntax.rst
│ └── utils/
│ ├── index.rst
│ └── searxng.sh.rst
├── go.mod
├── go.sum
├── manage
├── mise.toml
├── package.json
├── pyrightconfig.json
├── requirements-dev.txt
├── requirements-server.txt
├── requirements.txt
├── searx/
│ ├── __init__.py
│ ├── answerers/
│ │ ├── __init__.py
│ │ ├── _core.py
│ │ ├── random.py
│ │ └── statistics.py
│ ├── autocomplete.py
│ ├── babel_extract.py
│ ├── botdetection/
│ │ ├── __init__.py
│ │ ├── _helpers.py
│ │ ├── config.py
│ │ ├── http_accept.py
│ │ ├── http_accept_encoding.py
│ │ ├── http_accept_language.py
│ │ ├── http_connection.py
│ │ ├── http_sec_fetch.py
│ │ ├── http_user_agent.py
│ │ ├── ip_limit.py
│ │ ├── ip_lists.py
│ │ ├── link_token.py
│ │ ├── trusted_proxies.py
│ │ └── valkeydb.py
│ ├── brand.py
│ ├── cache.py
│ ├── compat.py
│ ├── data/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── ahmia_blacklist.txt
│ │ ├── core.py
│ │ ├── currencies.json
│ │ ├── currencies.py
│ │ ├── engine_descriptions.json
│ │ ├── engine_traits.json
│ │ ├── external_bangs.json
│ │ ├── external_urls.json
│ │ ├── gsa_useragents.txt
│ │ ├── lid.176.ftz
│ │ ├── locales.json
│ │ ├── osm_keys_tags.json
│ │ ├── tracker_patterns.py
│ │ ├── useragents.json
│ │ └── wikidata_units.json
│ ├── enginelib/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── traits.py
│ ├── engines/
│ │ ├── 1337x.py
│ │ ├── 360search.py
│ │ ├── 360search_videos.py
│ │ ├── 9gag.py
│ │ ├── __builtins__.pyi
│ │ ├── __init__.py
│ │ ├── acfun.py
│ │ ├── adobe_stock.py
│ │ ├── ahmia.py
│ │ ├── alpinelinux.py
│ │ ├── annas_archive.py
│ │ ├── ansa.py
│ │ ├── aol.py
│ │ ├── apkmirror.py
│ │ ├── apple_app_store.py
│ │ ├── apple_maps.py
│ │ ├── archlinux.py
│ │ ├── artic.py
│ │ ├── artstation.py
│ │ ├── arxiv.py
│ │ ├── astrophysics_data_system.py
│ │ ├── azure.py
│ │ ├── baidu.py
│ │ ├── bandcamp.py
│ │ ├── base.py
│ │ ├── bilibili.py
│ │ ├── bing.py
│ │ ├── bing_images.py
│ │ ├── bing_news.py
│ │ ├── bing_videos.py
│ │ ├── bitchute.py
│ │ ├── boardreader.py
│ │ ├── bpb.py
│ │ ├── brave.py
│ │ ├── braveapi.py
│ │ ├── bt4g.py
│ │ ├── btdigg.py
│ │ ├── cachy_os.py
│ │ ├── cara.py
│ │ ├── ccc_media.py
│ │ ├── chefkoch.py
│ │ ├── chinaso.py
│ │ ├── cloudflareai.py
│ │ ├── command.py
│ │ ├── core.py
│ │ ├── crates.py
│ │ ├── crossref.py
│ │ ├── currency_convert.py
│ │ ├── dailymotion.py
│ │ ├── deepl.py
│ │ ├── deezer.py
│ │ ├── demo_offline.py
│ │ ├── demo_online.py
│ │ ├── destatis.py
│ │ ├── deviantart.py
│ │ ├── devicons.py
│ │ ├── dictzone.py
│ │ ├── digbt.py
│ │ ├── discourse.py
│ │ ├── docker_hub.py
│ │ ├── doku.py
│ │ ├── duckduckgo.py
│ │ ├── duckduckgo_definitions.py
│ │ ├── duckduckgo_extra.py
│ │ ├── duckduckgo_weather.py
│ │ ├── duden.py
│ │ ├── dummy-offline.py
│ │ ├── dummy.py
│ │ ├── ebay.py
│ │ ├── elasticsearch.py
│ │ ├── emojipedia.py
│ │ ├── fdroid.py
│ │ ├── findthatmeme.py
│ │ ├── flickr.py
│ │ ├── flickr_noapi.py
│ │ ├── freesound.py
│ │ ├── frinkiac.py
│ │ ├── fyyd.py
│ │ ├── geizhals.py
│ │ ├── genius.py
│ │ ├── gitea.py
│ │ ├── github.py
│ │ ├── github_code.py
│ │ ├── gitlab.py
│ │ ├── gmx.py
│ │ ├── goodreads.py
│ │ ├── google.py
│ │ ├── google_images.py
│ │ ├── google_news.py
│ │ ├── google_play.py
│ │ ├── google_scholar.py
│ │ ├── google_videos.py
│ │ ├── grokipedia.py
│ │ ├── hackernews.py
│ │ ├── hex.py
│ │ ├── huggingface.py
│ │ ├── il_post.py
│ │ ├── imdb.py
│ │ ├── imgur.py
│ │ ├── ina.py
│ │ ├── invidious.py
│ │ ├── ipernity.py
│ │ ├── iqiyi.py
│ │ ├── jisho.py
│ │ ├── json_engine.py
│ │ ├── karmasearch.py
│ │ ├── kickass.py
│ │ ├── lemmy.py
│ │ ├── lib_rs.py
│ │ ├── libretranslate.py
│ │ ├── lingva.py
│ │ ├── loc.py
│ │ ├── lucide.py
│ │ ├── marginalia.py
│ │ ├── mariadb_server.py
│ │ ├── mastodon.py
│ │ ├── material_icons.py
│ │ ├── mediathekviewweb.py
│ │ ├── mediawiki.py
│ │ ├── meilisearch.py
│ │ ├── metacpan.py
│ │ ├── microsoft_learn.py
│ │ ├── mixcloud.py
│ │ ├── mojeek.py
│ │ ├── mongodb.py
│ │ ├── moviepilot.py
│ │ ├── mozhi.py
│ │ ├── mrs.py
│ │ ├── mwmbl.py
│ │ ├── mysql_server.py
│ │ ├── naver.py
│ │ ├── niconico.py
│ │ ├── npm.py
│ │ ├── nvd.py
│ │ ├── nyaa.py
│ │ ├── odysee.py
│ │ ├── ollama.py
│ │ ├── open_meteo.py
│ │ ├── openalex.py
│ │ ├── openclipart.py
│ │ ├── openlibrary.py
│ │ ├── opensemantic.py
│ │ ├── openstreetmap.py
│ │ ├── openverse.py
│ │ ├── pdbe.py
│ │ ├── peertube.py
│ │ ├── pexels.py
│ │ ├── photon.py
│ │ ├── pinterest.py
│ │ ├── piped.py
│ │ ├── piratebay.py
│ │ ├── pixabay.py
│ │ ├── pixiv.py
│ │ ├── pkg_go_dev.py
│ │ ├── podcastindex.py
│ │ ├── postgresql.py
│ │ ├── presearch.py
│ │ ├── public_domain_image_archive.py
│ │ ├── pubmed.py
│ │ ├── pypi.py
│ │ ├── quark.py
│ │ ├── qwant.py
│ │ ├── radio_browser.py
│ │ ├── recoll.py
│ │ ├── reddit.py
│ │ ├── repology.py
│ │ ├── reuters.py
│ │ ├── rottentomatoes.py
│ │ ├── rumble.py
│ │ ├── scanr_structures.py
│ │ ├── searx_engine.py
│ │ ├── selfhst.py
│ │ ├── semantic_scholar.py
│ │ ├── senscritique.py
│ │ ├── sepiasearch.py
│ │ ├── seznam.py
│ │ ├── sogou.py
│ │ ├── sogou_images.py
│ │ ├── sogou_videos.py
│ │ ├── sogou_wechat.py
│ │ ├── solidtorrents.py
│ │ ├── solr.py
│ │ ├── soundcloud.py
│ │ ├── sourcehut.py
│ │ ├── spotify.py
│ │ ├── springer.py
│ │ ├── sqlite.py
│ │ ├── stackexchange.py
│ │ ├── startpage.py
│ │ ├── steam.py
│ │ ├── svgrepo.py
│ │ ├── tagesschau.py
│ │ ├── tineye.py
│ │ ├── tokyotoshokan.py
│ │ ├── tootfinder.py
│ │ ├── torznab.py
│ │ ├── translated.py
│ │ ├── tubearchivist.py
│ │ ├── unsplash.py
│ │ ├── uxwing.py
│ │ ├── valkey_server.py
│ │ ├── vimeo.py
│ │ ├── voidlinux.py
│ │ ├── wallhaven.py
│ │ ├── wikicommons.py
│ │ ├── wikidata.py
│ │ ├── wikipedia.py
│ │ ├── wolframalpha_api.py
│ │ ├── wolframalpha_noapi.py
│ │ ├── wordnik.py
│ │ ├── wttr.py
│ │ ├── www1x.py
│ │ ├── xpath.py
│ │ ├── yacy.py
│ │ ├── yahoo.py
│ │ ├── yahoo_news.py
│ │ ├── yandex.py
│ │ ├── yandex_music.py
│ │ ├── yep.py
│ │ ├── youtube_api.py
│ │ ├── youtube_noapi.py
│ │ └── zlibrary.py
│ ├── exceptions.py
│ ├── extended_types.py
│ ├── external_bang.py
│ ├── external_urls.py
│ ├── favicons/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── cache.py
│ │ ├── config.py
│ │ ├── favicons.toml
│ │ ├── proxy.py
│ │ └── resolvers.py
│ ├── flaskfix.py
│ ├── infopage/
│ │ ├── __init__.py
│ │ ├── de/
│ │ │ ├── about.md
│ │ │ ├── donate.md
│ │ │ └── search-syntax.md
│ │ ├── en/
│ │ │ ├── about.md
│ │ │ ├── donate.md
│ │ │ └── search-syntax.md
│ │ ├── fa_IR/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ ├── fr/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ ├── id/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ └── it/
│ │ ├── about.md
│ │ └── search-syntax.md
│ ├── limiter.py
│ ├── limiter.toml
│ ├── locales.py
│ ├── metrics/
│ │ ├── __init__.py
│ │ ├── error_recorder.py
│ │ └── models.py
│ ├── network/
│ │ ├── __init__.py
│ │ ├── client.py
│ │ ├── network.py
│ │ └── raise_for_httperror.py
│ ├── openmetrics.py
│ ├── plugins/
│ │ ├── __init__.py
│ │ ├── _core.py
│ │ ├── ahmia_filter.py
│ │ ├── calculator.py
│ │ ├── hash_plugin.py
│ │ ├── hostnames.py
│ │ ├── infinite_scroll.py
│ │ ├── oa_doi_rewrite.py
│ │ ├── self_info.py
│ │ ├── time_zone.py
│ │ ├── tor_check.py
│ │ ├── tracker_url_remover.py
│ │ └── unit_converter.py
│ ├── preferences.py
│ ├── query.py
│ ├── result_types/
│ │ ├── __init__.py
│ │ ├── _base.py
│ │ ├── answer.py
│ │ ├── code.py
│ │ ├── file.py
│ │ ├── keyvalue.py
│ │ └── paper.py
│ ├── results.py
│ ├── search/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── processors/
│ │ ├── __init__.py
│ │ ├── abstract.py
│ │ ├── offline.py
│ │ ├── online.py
│ │ ├── online_currency.py
│ │ ├── online_dictionary.py
│ │ └── online_url_search.py
│ ├── searxng.msg
│ ├── settings.yml
│ ├── settings_defaults.py
│ ├── settings_loader.py
│ ├── sqlitedb.py
│ ├── static/
│ │ └── themes/
│ │ └── simple/
│ │ └── manifest.json
│ ├── sxng_locales.py
│ ├── templates/
│ │ └── simple/
│ │ ├── 404.html
│ │ ├── answer/
│ │ │ ├── legacy.html
│ │ │ ├── translations.html
│ │ │ └── weather.html
│ │ ├── base.html
│ │ ├── categories.html
│ │ ├── elements/
│ │ │ ├── answers.html
│ │ │ ├── apis.html
│ │ │ ├── corrections.html
│ │ │ ├── engines_msg.html
│ │ │ ├── infobox.html
│ │ │ ├── search_url.html
│ │ │ └── suggestions.html
│ │ ├── filters/
│ │ │ ├── languages.html
│ │ │ ├── safesearch.html
│ │ │ └── time_range.html
│ │ ├── icons.html
│ │ ├── index.html
│ │ ├── info.html
│ │ ├── macros.html
│ │ ├── manifest.json
│ │ ├── messages/
│ │ │ ├── no_cookies.html
│ │ │ └── no_results.html
│ │ ├── new_issue.html
│ │ ├── opensearch.xml
│ │ ├── opensearch_response_rss.xml
│ │ ├── page_with_header.html
│ │ ├── preferences/
│ │ │ ├── answerers.html
│ │ │ ├── autocomplete.html
│ │ │ ├── center_alignment.html
│ │ │ ├── cookies.html
│ │ │ ├── doi_resolver.html
│ │ │ ├── engines.html
│ │ │ ├── favicon.html
│ │ │ ├── footer.html
│ │ │ ├── hotkeys.html
│ │ │ ├── image_proxy.html
│ │ │ ├── language.html
│ │ │ ├── method.html
│ │ │ ├── query_in_title.html
│ │ │ ├── results_on_new_tab.html
│ │ │ ├── safesearch.html
│ │ │ ├── search_on_category_select.html
│ │ │ ├── theme.html
│ │ │ ├── tokens.html
│ │ │ ├── ui_locale.html
│ │ │ └── urlformatting.html
│ │ ├── preferences.html
│ │ ├── result_templates/
│ │ │ ├── code.html
│ │ │ ├── default.html
│ │ │ ├── file.html
│ │ │ ├── images.html
│ │ │ ├── keyvalue.html
│ │ │ ├── map.html
│ │ │ ├── packages.html
│ │ │ ├── paper.html
│ │ │ ├── products.html
│ │ │ ├── torrent.html
│ │ │ └── videos.html
│ │ ├── results.html
│ │ ├── rss.xsl
│ │ ├── search.html
│ │ ├── simple_search.html
│ │ └── stats.html
│ ├── translations/
│ │ ├── af/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ar/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bg/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bn/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bo/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ca/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── cs/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── cy/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── da/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── de/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── dv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── el_GR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── en/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── eo/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── es/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── et/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── eu/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fa_IR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fi/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fil/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ga/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── gl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── he/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── hr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── hu/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ia/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── id/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── it/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ja/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ko/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── lt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── lv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── messages.pot
│ │ ├── ml/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ms/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── nb_NO/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── nl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── oc/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pa/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pap/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt_BR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ro/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ru/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── si/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── szl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ta/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── te/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── th/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── tr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── tt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── uk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── vi/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── zh_Hans_CN/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ └── zh_Hant_TW/
│ │ └── LC_MESSAGES/
│ │ ├── messages.mo
│ │ └── messages.po
│ ├── utils.py
│ ├── valkeydb.py
│ ├── valkeylib.py
│ ├── version.py
│ ├── weather.py
│ ├── webadapter.py
│ ├── webapp.py
│ ├── webutils.py
│ └── wikidata_units.py
├── searxng_extra/
│ ├── __init__.py
│ ├── docs_prebuild
│ └── update/
│ ├── __init__.py
│ ├── update_ahmia_blacklist.py
│ ├── update_currencies.py
│ ├── update_engine_descriptions.py
│ ├── update_engine_traits.py
│ ├── update_external_bangs.py
│ ├── update_firefox_version.py
│ ├── update_gsa_useragents.py
│ ├── update_locales.py
│ ├── update_osm_keys_tags.py
│ ├── update_pygments.py
│ └── update_wikidata_units.py
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── robot/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── settings_robot.yml
│ │ └── test_webapp.py
│ └── unit/
│ ├── __init__.py
│ ├── engines/
│ │ ├── __init__.py
│ │ ├── test_command.py
│ │ ├── test_json_engine.py
│ │ └── test_xpath.py
│ ├── network/
│ │ ├── __init__.py
│ │ └── test_network.py
│ ├── processors/
│ │ ├── __init__.py
│ │ └── test_online.py
│ ├── settings/
│ │ ├── empty_settings.yml
│ │ ├── limiter.toml
│ │ ├── syntaxerror_settings.yml
│ │ ├── test_github_code.yml
│ │ ├── test_result_container.yml
│ │ ├── test_settings.yml
│ │ ├── test_tineye.yml
│ │ ├── user_settings.yml
│ │ ├── user_settings_keep_only.yml
│ │ ├── user_settings_remove.yml
│ │ ├── user_settings_remove2.yml
│ │ └── user_settings_simple.yml
│ ├── test_answerers.py
│ ├── test_engine_github_code.py
│ ├── test_engine_tineye.py
│ ├── test_engines_init.py
│ ├── test_exceptions.py
│ ├── test_external_bangs.py
│ ├── test_js_variable_to_python.py
│ ├── test_locales.py
│ ├── test_plugin_hash.py
│ ├── test_plugin_self_info.py
│ ├── test_plugins.py
│ ├── test_preferences.py
│ ├── test_query.py
│ ├── test_results.py
│ ├── test_search.py
│ ├── test_settings_loader.py
│ ├── test_utils.py
│ ├── test_webadapter.py
│ ├── test_webapp.py
│ └── test_webutils.py
└── utils/
├── brand.sh
├── get_setting.py
├── lib.sh
├── lib_govm.sh
├── lib_nvm.sh
├── lib_redis.sh
├── lib_sxng_container.sh
├── lib_sxng_data.sh
├── lib_sxng_node.sh
├── lib_sxng_static.sh
├── lib_sxng_test.sh
├── lib_sxng_themes.sh
├── lib_sxng_vite.sh
├── lib_sxng_weblate.sh
├── lib_valkey.sh
├── makefile.include
├── searxng.sh
├── searxng_check.py
└── templates/
└── etc/
├── apt/
│ └── sources.list.d/
│ ├── debian-stable-backports.sources
│ └── ubuntu-stable-backports.sources
├── httpd/
│ └── sites-available/
│ ├── searxng.conf
│ └── searxng.conf:socket
├── nginx/
│ └── default.apps-available/
│ ├── searxng.conf
│ └── searxng.conf:socket
├── searxng/
│ └── settings.yml
└── uwsgi/
├── apps-archlinux/
│ ├── searxng.ini
│ └── searxng.ini:socket
└── apps-available/
├── searxng.ini
└── searxng.ini:socket
================================================
FILE CONTENTS
================================================
================================================
FILE: .coveragerc
================================================
[run]
branch = True
source = searx
[report]
show_missing = True
exclude_lines =
if __name__ == .__main__.:
[html]
directory = coverage
================================================
FILE: .devcontainer/Dockerfile
================================================
ARG DEBIAN_CODENAME="bookworm"
FROM mcr.microsoft.com/devcontainers/base:$DEBIAN_CODENAME
ARG DEBIAN_CODENAME="bookworm"
RUN cat <<EOF > /etc/apt/sources.list.d/debian.sources
Types: deb
URIs: http://deb.debian.org/debian
Suites: $DEBIAN_CODENAME $DEBIAN_CODENAME-updates $DEBIAN_CODENAME-backports
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: http://security.debian.org/debian-security
Suites: $DEBIAN_CODENAME-security
Components: main
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF
RUN apt-get update && \
apt-get -y install python3 python3-venv valkey-server firefox-esr graphviz imagemagick librsvg2-bin fonts-dejavu shellcheck
================================================
FILE: .devcontainer/devcontainer.json
================================================
{
"build": {
"args": {
"DEBIAN_CODENAME": "bookworm",
},
"dockerfile": "Dockerfile"
},
"features": {
"ghcr.io/devcontainers/features/github-cli": {},
"ghcr.io/devcontainers/features/docker-in-docker": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-azuretools.vscode-docker"
],
"remote.otherPortsAttributes": {
"protocol": "https"
},
"settings": {
"files.autoSave": "off",
"python.defaultInterpreterPath": "/workspaces/searxng/local/py3/bin/python3",
"python.formatting.blackPath": "/workspaces/searxng/local/py3/bin/black",
"python.linting.pylintPath": "/workspaces/searxng/local/py3/bin/pylint"
}
}
},
"forwardPorts": [8000, 8888],
"portsAttributes": {
"8000": {"label": "Sphinx documentation"},
"8888": {"label": "SearXNG"}
},
"postCreateCommand": "git pull && make install"
}
================================================
FILE: .dir-locals-template.el
================================================
;;; .dir-locals.el
;;
;; Per-Directory Local Variables:
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Directory-Variables.html
;;
;; For full fledge developer tools install emacs packages:
;;
;; M-x package-install ...
;;
;; magit gitconfig
;; nvm lsp-mode lsp-pyright lsp-eslint
;; pyvenv pylint pip-requirements
;; jinja2-mode
;; json-mode
;; company company-jedi company-quickhelp company-shell
;; realgud
;; sphinx-doc markdown-mode graphviz-dot-mode
;; apache-mode nginx-mode
;;
;; To setup a developer environment, build target::
;;
;; $ make node.env.dev pyenv.install
;;
;; Some buffer locals are referencing the project environment:
;;
;; - prj-root --> <repo>/
;; - nvm-dir --> <repo>/.nvm
;; - python-environment-directory --> <repo>/local
;; - python-environment-default-root-name --> py3
;; - python-shell-virtualenv-root --> <repo>/local/py3
;; When this variable is set with the path of the virtualenv to use,
;; `process-environment' and `exec-path' get proper values in order to run
;; shells inside the specified virtualenv, example::
;; (setq python-shell-virtualenv-root "/path/to/env/")
;; - python-shell-interpreter --> <repo>/local/py3/bin/python
;;
;; Python development:
;;
;; Jedi, flycheck & other python stuff should use the 'python-shell-interpreter'
;; from the local py3 environment.
;;
((nil
. ((fill-column . 80)
(indent-tabs-mode . nil)
(eval . (progn
(add-to-list 'auto-mode-alist '("\\.html\\'" . jinja2-mode))
;; project root folder is where the `.dir-locals.el' is located
(setq-local prj-root
(locate-dominating-file default-directory ".dir-locals.el"))
(setq-local python-environment-directory
(expand-file-name "./local" prj-root))
;; to get in use of NVM environment, install https://github.com/rejeep/nvm.el
(setq-local nvm-dir (expand-file-name "./.nvm" prj-root))
;; use nodejs from the (local) NVM environment (see nvm-dir)
(nvm-use-for-buffer)
(ignore-errors (require 'lsp))
(setq-local lsp-server-install-dir (car (cdr nvm-current-version)))
(setq-local lsp-enable-file-watchers nil)
;; use 'py3' environment as default
(setq-local python-environment-default-root-name
"py3")
(setq-local python-shell-virtualenv-root
(expand-file-name
python-environment-default-root-name python-environment-directory))
(setq-local python-shell-interpreter
(expand-file-name
"bin/python" python-shell-virtualenv-root))))))
(makefile-gmake-mode
. ((indent-tabs-mode . t)))
(yaml-mode
. ((eval . (progn
;; flycheck should use the local py3 environment
(setq-local flycheck-yaml-yamllint-executable
(expand-file-name "bin/yamllint" python-shell-virtualenv-root))
(setq-local flycheck-yamllintrc
(expand-file-name ".yamllint.yml" prj-root))
(flycheck-checker . yaml-yamllint)))))
(json-mode
. ((eval . (progn
(setq-local js-indent-level 4)
(flycheck-checker . json-python-json)))))
(js-mode
. ((eval . (progn
(ignore-errors (require 'lsp-eslint))
(setq-local js-indent-level 2)
;; flycheck should use the eslint checker from developer tools
(setq-local flycheck-javascript-eslint-executable
(expand-file-name "node_modules/.bin/eslint" prj-root))
;; (flycheck-mode)
(if (featurep 'lsp-eslint)
(lsp))
))))
(python-mode
. ((eval . (progn
(ignore-errors (require 'jedi-core))
(ignore-errors (require 'lsp-pyright))
(ignore-errors (sphinx-doc-mode))
(setq-local python-environment-virtualenv
(list (expand-file-name "bin/virtualenv" python-shell-virtualenv-root)
;;"--system-site-packages"
"--quiet"))
(setq-local pylint-command
(expand-file-name "bin/pylint" python-shell-virtualenv-root))
(if (featurep 'lsp-pyright)
(lsp))
;; pylint will find the '.pylintrc' file next to the CWD
;; https://pylint.readthedocs.io/en/latest/user_guide/run.html#command-line-options
(setq-local flycheck-pylintrc
".pylintrc")
;; flycheck & other python stuff should use the local py3 environment
(setq-local flycheck-python-pylint-executable
python-shell-interpreter)
;; use 'M-x jedi:show-setup-info' and 'M-x epc:controller' to inspect jedi server
;; https://tkf.github.io/emacs-jedi/latest/#jedi:environment-root -- You
;; can specify a full path instead of a name (relative path). In that case,
;; python-environment-directory is ignored and Python virtual environment
;; is created at the specified path.
(setq-local jedi:environment-root
python-shell-virtualenv-root)
;; https://tkf.github.io/emacs-jedi/latest/#jedi:server-command
(setq-local jedi:server-command
(list python-shell-interpreter
jedi:server-script))
;; jedi:environment-virtualenv --> see above 'python-environment-virtualenv'
;; is set buffer local! No need to setup jedi:environment-virtualenv:
;;
;; Virtualenv command to use. A list of string. If it is nil,
;; python-environment-virtualenv is used instead. You must set non-nil
;; value to jedi:environment-root in order to make this setting work.
;;
;; https://tkf.github.io/emacs-jedi/latest/#jedi:environment-virtualenv
;;
;; (setq-local jedi:environment-virtualenv
;; (list (expand-file-name "bin/virtualenv" python-shell-virtualenv-root)
;; "--python"
;; "/usr/bin/python3.4"
;; ))
))))
)
================================================
FILE: .dockerignore
================================================
*
!container/entrypoint.sh
!searx/**
!requirements*.txt
================================================
FILE: .editorconfig
================================================
# https://editorconfig.org/
root = true
[*]
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
end_of_line = lf
charset = utf-8
[{*.py,*.pyi}]
# code formatter accepts length of 120, but editor should prefer 80
max_line_length = 80
[{*.sh,manage}]
indent_style = space
indent_size = 4
# shfmt options
shell_variant = bash
switch_case_indent = true
[*.html]
# in the jinja templates we use indent size of 2 and we do not use tabs
indent_size = 2
indent_style = space
[*.css]
indent_size = 2
[*.less]
indent_size = 2
[*.js]
indent_size = 2
[*.ts]
indent_size = 2
[*.json]
indent_size = 2
insert_final_newline = ignore
[*.map]
indent_size = ignore
insert_final_newline = ignore
# Minified JavaScript files shouldn't be changed
[*.min.js]
indent_style = ignore
insert_final_newline = ignore
# Minified CSS files shouldn't be changed
[*.min.css]
indent_style = ignore
insert_final_newline = ignore
# Makefiles always use tabs for indentation
[Makefile]
indent_style = tab
# Batch files use tabs for indentation
[*.bat]
indent_style = tab
[docs/**.rst]
max_line_length = 79
[*.yml]
indent_size = 2
================================================
FILE: .gitattributes
================================================
*.gif -diff
*.png -diff
*.min.css -diff
*.min.js -diff
*.css.map -diff
*.js.map -diff
*.eot -diff
*.svg -diff
*.ttf -diff
*.woff -diff
*.woff2 -diff
messages.mo -diff
================================================
FILE: .github/FUNDING.yml
================================================
github: [tiekoettercom]
custom: https://www.tiekoetter.com/donate/
================================================
FILE: .github/ISSUE_TEMPLATE/bug-report.md
================================================
---
name: "Bug report"
about: Report a bug in SearXNG"
labels: ["bug"]
type: "bug"
---
_Replace this placeholder with a meaningful and precise description of the bug._
<!-- FILL IN THESE FIELDS .. and delete the comments after reading.
Use Markdown for formatting -> https://www.markdowntools.io/cheat-sheet
-->
### How To Reproduce?
<!-- How can we reproduce this issue? (as minimally and as precisely as
possible) -->
### Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
### Screenshots & Logs
<!-- If applicable, add screenshots, logs to help explain your problem. -->
### Version of SearXNG
<!-- Commit number if you are using on master branch and stipulate if you forked
SearXNG -->
<!-- Look at the bottom of the SearXNG page and check for the version after
"Powered by SearXNG" If you are using a forked version of SearXNG include a
link to the fork source code. -->
### How did you install SearXNG?
<!-- Did you install SearXNG using the official documentation or using
searxng-docker? -->
### Additional context
<!-- Add any other context about the problem here. -->
### Code of Conduct
[AI Policy]: https://github.com/searxng/searxng/blob/master/AI_POLICY.rst
- [ ] I read the [AI Policy] and hereby confirm that this issue conforms with the policy.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Questions & Answers (Q&A)
url: https://github.com/searxng/searxng/discussions/categories/q-a
about: Ask questions and find answers
================================================
FILE: .github/ISSUE_TEMPLATE/engine-request.md
================================================
---
name: Engine request"
about: Request a new engine in SearXNG"
labels: ["engine request"]
type: "feature"
---
<!-- FILL IN THESE FIELDS .. and delete the comments after reading.
Use Markdown for formatting -> https://www.markdowntools.io/cheat-sheet
-->
### Working URL to the engine
<!-- Please check if the engine is responding correctly before submitting -->
### Why do you want to add this engine?
<!-- What's special about this engine? -->
### Features of this engine
<!-- Features of this engine: Serves special content, is fast, is easy to
integrate, ... ? -->
### How can SearXNG fetch results from this engine?
<!-- List API URL, example code and more that could be useful for the developers
in order to implement this engine. If you don't know what to write, let
this part blank. -->
### Applicable category of this engine
<!-- Where should this new engine fit in SearXNG? Current categories in
SearXNG: general, files, images, it, map, music, news, science, social
media and videos. -->
### Additional context
<!-- Add any other context about the problem here. -->
### Code of Conduct
[AI Policy]: https://github.com/searxng/searxng/blob/master/AI_POLICY.rst
- [ ] I read the [AI Policy] and hereby confirm that this issue conforms with the policy.
================================================
FILE: .github/ISSUE_TEMPLATE/feature-request.md
================================================
---
name: "Feature request"
about: "Request a new feature in SearXNG"
labels: ["new feature"]
type: "feature"
---
_Replace this placeholder with a concise description of the feature._
<!-- FILL IN THESE FIELDS .. and delete the comments after reading.
Use Markdown for formatting -> https://www.markdowntools.io/cheat-sheet
-->
### Is your feature request related to a problem?
<!-- A clear and concise description of what the problem is. Ex. I'm always
frustrated when [...] -->
### Describe the solution you'd like
<!-- A clear and concise description of what you want to happen. -->
### Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
### Code of Conduct
[AI Policy]: https://github.com/searxng/searxng/blob/master/AI_POLICY.rst
- [ ] I read the [AI Policy] and hereby confirm that this issue conforms with the policy.
================================================
FILE: .github/dependabot.yml
================================================
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
open-pull-requests-limit: 5
target-branch: "master"
commit-message:
prefix: "[upd] pypi:"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "npm"
directory: "/client/simple"
schedule:
interval: "weekly"
day: "friday"
open-pull-requests-limit: 5
target-branch: "master"
commit-message:
prefix: "[upd] web-client (simple):"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
open-pull-requests-limit: 5
target-branch: "master"
commit-message:
prefix: "[upd] searxng.org/devtools (Node.js):"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "gomod"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
open-pull-requests-limit: 5
target-branch: "master"
commit-message:
prefix: "[upd] searxng.org/devtools (Go):"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
target-branch: "master"
commit-message:
prefix: "[upd] github-actions:"
================================================
FILE: .github/workflows/container.yml
================================================
---
name: Container
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
workflow_run:
workflows:
- Integration
types:
- completed
branches:
- master
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
packages: write
env:
PYTHON_VERSION: "3.14"
jobs:
build:
if: github.repository_owner == 'tiekoetter' || github.event_name == 'workflow_dispatch'
name: Build (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
march: amd64
os: ubuntu-24.04
emulation: false
- arch: arm64
march: arm64
os: ubuntu-24.04-arm
emulation: false
- arch: armv7
march: arm64
os: ubuntu-24.04-arm
emulation: true
permissions:
packages: write
outputs:
docker_tag: ${{ steps.build.outputs.docker_tag }}
git_url: ${{ steps.build.outputs.git_url }}
steps:
# yamllint disable rule:line-length
- name: Setup podman
env:
PODMAN_VERSION: "v5.7.1"
run: |
sudo apt-get purge -y podman runc crun conmon
curl -fsSLO "https://github.com/mgoltzsche/podman-static/releases/download/${{ env.PODMAN_VERSION }}/podman-linux-${{ matrix.march }}.tar.gz"
curl -fsSLO "https://github.com/mgoltzsche/podman-static/releases/download/${{ env.PODMAN_VERSION }}/podman-linux-${{ matrix.march }}.tar.gz.asc"
gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 0CCF102C4F95D89E583FF1D4F8B5AF50344BB503
gpg --batch --verify "podman-linux-${{ matrix.march }}.tar.gz.asc" "podman-linux-${{ matrix.march }}.tar.gz"
tar -xzf "podman-linux-${{ matrix.march }}.tar.gz"
sudo cp -rfv ./podman-linux-${{ matrix.march }}/etc/. /etc/
sudo cp -rfv ./podman-linux-${{ matrix.march }}/usr/. /usr/
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
# yamllint enable rule:line-length
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Get date
id: date
run: echo "date=$(date +'%Y%m%d')" >>$GITHUB_OUTPUT
- name: Setup cache container
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "container-${{ matrix.arch }}-${{ steps.date.outputs.date }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
container-${{ matrix.arch }}-${{ steps.date.outputs.date }}-
container-${{ matrix.arch }}-
path: "/var/tmp/buildah-cache-*/*"
- if: ${{ matrix.emulation }}
name: Setup QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: Build
id: build
env:
OVERRIDE_ARCH: "${{ matrix.arch }}"
run: make podman.build
test:
name: Test (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
needs: build
strategy:
fail-fast: false
matrix:
include:
- arch: amd64
os: ubuntu-24.04
emulation: false
- arch: arm64
os: ubuntu-24.04-arm
emulation: false
- arch: armv7
os: ubuntu-24.04-arm
emulation: true
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- if: ${{ matrix.emulation }}
name: Setup QEMU
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: Test
env:
OVERRIDE_ARCH: "${{ matrix.arch }}"
GIT_URL: "${{ needs.build.outputs.git_url }}"
run: make container.test
release:
if: github.repository_owner == 'tiekoetter' && github.ref_name == 'master'
name: Release
runs-on: ubuntu-24.04-arm
needs:
- build
- test
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- name: Login to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: Release
env:
GIT_URL: "${{ needs.build.outputs.git_url }}"
DOCKER_TAG: "${{ needs.build.outputs.docker_tag }}"
run: make container.push
================================================
FILE: .github/workflows/data-update.yml
================================================
---
name: Update searx.data
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
schedule:
- cron: "59 23 28 * *"
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
env:
PYTHON_VERSION: "3.14"
jobs:
data:
if: github.repository_owner == 'searxng'
name: ${{ matrix.fetch }}
runs-on: ubuntu-24.04-arm
strategy:
fail-fast: false
matrix:
fetch:
- update_ahmia_blacklist.py
- update_currencies.py
- update_external_bangs.py
- update_firefox_version.py
- update_engine_traits.py
- update_wikidata_units.py
- update_engine_descriptions.py
- update_gsa_useragents.py
permissions:
contents: write
pull-requests: write
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Fetch data
run: V=1 ./manage pyenv.cmd python "./searxng_extra/update/${{ matrix.fetch }}"
- name: Create PR
id: cpr
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
author: "searxng-bot <searxng-bot@users.noreply.github.com>"
committer: "searxng-bot <searxng-bot@users.noreply.github.com>"
title: "[data] update searx.data - ${{ matrix.fetch }}"
commit-message: "[data] update searx.data - ${{ matrix.fetch }}"
branch: "update_data_${{ matrix.fetch }}"
delete-branch: "true"
draft: "false"
signoff: "false"
body: |
[data] update searx.data - ${{ matrix.fetch }}
labels: |
data
- name: Display information
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
================================================
FILE: .github/workflows/documentation.yml
================================================
---
name: Documentation
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
env:
PYTHON_VERSION: "3.14"
jobs:
release:
if: github.repository_owner == 'searxng' || github.event_name == 'workflow_dispatch'
name: Release
runs-on: ubuntu-24.04-arm
permissions:
# for JamesIves/github-pages-deploy-action to push
contents: write
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Build documentation
run: make V=1 docs.clean docs.html
- if: github.ref_name == 'master'
name: Release
uses: JamesIves/github-pages-deploy-action@d92aa235d04922e8f08b40ce78cc5442fcfbfa2f # v4.8.0
with:
folder: "dist/docs"
branch: "gh-pages"
commit-message: "[doc] build from commit ${{ github.sha }}"
# Automatically remove deleted files from the deploy branch
clean: "true"
single-commit: "true"
================================================
FILE: .github/workflows/integration.yml
================================================
---
name: Integration
# yamllint disable-line rule:truthy
on:
push:
branches:
- master
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: read
env:
PYTHON_VERSION: "3.14"
jobs:
test:
name: Python ${{ matrix.python-version }}
runs-on: ubuntu-24.04
strategy:
matrix:
python-version:
- "3.11"
- "3.12"
- "3.13"
- "3.14"
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ matrix.python-version }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ matrix.python-version }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ matrix.python-version }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Run tests
run: make V=1 ci.test
theme:
name: Theme
runs-on: ubuntu-24.04-arm
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- name: Setup Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version-file: "./.nvmrc"
- name: Setup cache Node.js
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "nodejs-${{ runner.arch }}-${{ hashFiles('./.nvmrc', './package.json') }}"
path: "./client/simple/node_modules/"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Lint
run: make themes.lint
- name: Build
run: make themes.all
================================================
FILE: .github/workflows/l10n.yml
================================================
---
name: Translation
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
workflow_run:
workflows:
- Integration
types:
- completed
branches:
- master
schedule:
- cron: "05 07 * * 5"
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
env:
PYTHON_VERSION: "3.14"
jobs:
update:
if: github.repository_owner == 'searxng' && github.event.workflow_run.conclusion == 'success'
name: Update
runs-on: ubuntu-24.04-arm
permissions:
# For "make V=1 weblate.push.translations"
contents: write
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: "${{ secrets.WEBLATE_GITHUB_TOKEN }}"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Setup Weblate
run: |
mkdir -p ~/.config
echo "${{ secrets.WEBLATE_CONFIG }}" > ~/.config/weblate
- name: Setup Git
run: |
git config --global user.email "searxng-bot@users.noreply.github.com"
git config --global user.name "searxng-bot"
- name: Update translations
run: make V=1 weblate.push.translations
pr:
if: |
github.repository_owner == 'searxng'
&& (github.event_name == 'workflow_dispatch' || github.event_name == 'schedule')
name: Pull Request
runs-on: ubuntu-24.04-arm
permissions:
# For "make V=1 weblate.translations.commit"
contents: write
# For action "peter-evans/create-pull-request"
pull-requests: write
steps:
- name: Setup Python
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: "${{ secrets.WEBLATE_GITHUB_TOKEN }}"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: |
python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-
path: "./local/"
- name: Setup venv
run: make V=1 install
- name: Setup Weblate
run: |
mkdir -p ~/.config
echo "${{ secrets.WEBLATE_CONFIG }}" > ~/.config/weblate
- name: Setup Git
run: |
git config --global user.email "searxng-bot@users.noreply.github.com"
git config --global user.name "searxng-bot"
- name: Merge and push translation updates
run: make V=1 weblate.translations.commit
- name: Create PR
id: cpr
uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1
with:
author: "searxng-bot <searxng-bot@users.noreply.github.com>"
committer: "searxng-bot <searxng-bot@users.noreply.github.com>"
title: "[l10n] update translations from Weblate"
commit-message: "[l10n] update translations from Weblate"
branch: "translations_update"
delete-branch: "true"
draft: "false"
signoff: "false"
body: |
[l10n] update translations from Weblate
labels: |
area:i18n
- name: Display information
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
================================================
FILE: .github/workflows/security.yml
================================================
---
name: Security
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
schedule:
- cron: "42 05 * * *"
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
jobs:
container:
if: github.repository_owner == 'searxng'
name: Container
runs-on: ubuntu-24.04-arm
permissions:
security-events: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: "false"
- name: Sync GHCS from Docker Scout
uses: docker/scout-action@bacf462e8d090c09660de30a6ccc718035f961e3 # v1.20.4
with:
organization: "searxng"
dockerhub-user: "${{ secrets.DOCKER_USER }}"
dockerhub-password: "${{ secrets.DOCKER_TOKEN }}"
image: "registry://ghcr.io/searxng/searxng:latest"
command: "cves"
sarif-file: "./scout.sarif"
exit-code: "false"
write-comment: "false"
- name: Upload SARIFs
uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
with:
sarif_file: "./scout.sarif"
================================================
FILE: .gitignore
================================================
# to sync with .dockerignore & pyrightconfig.json
*.pyc
*/*.pyc
*~
*.swp
geckodriver.log
.coverage
coverage/
.govm/
.nvm/
cache/
build/
dist/
local/
gh-pages/
*.egg-info/
/package-lock.json
/node_modules/
.idea/
searx/version_frozen.py
.dir-locals.el
.python-version
================================================
FILE: .nvmrc
================================================
25
================================================
FILE: .pylintrc
================================================
# -*- coding: utf-8; mode: conf-unix -*-
# lint Python modules using external checkers.
#
# This is the main checker controlling the other ones and the reports
# generation. It is itself both a raw checker and an astng checker in order
# to:
# * handle message activation / deactivation at the module level
# * handle some basic but necessary stats'data (number of classes, methods...)
#
[MASTER]
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=lxml.etree
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS, .git, .svn
# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
ignore-patterns=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Use multiple processes to speed up Pylint.
jobs=0
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Pickle collected data for later comparisons.
persistent=yes
# Specify a configuration file.
#rcfile=
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=duplicate-code,
missing-function-docstring,
consider-using-f-string,
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
enable=
[REPORTS]
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
# HINT: do not set this here, use argument --msg-template=...
#msg-template={path}:{line}: [{msg_id}({symbol}),{obj}] {msg}
# Set the output format. Available formats are text, parseable, colorized, json
# and msvs (visual studio).You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
# HINT: do not set this here, use argument --output-format=...
#output-format=text
# Tells whether to display a full report or only the messages
reports=no
# Activate the evaluation score.
score=yes
[REFACTORING]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[BASIC]
# Regular expression matching correct argument names
argument-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct attribute names
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*)|([A-Z0-9_]*))$
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Regular expression matching correct constant names
const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$
#const-rgx=[f]?[A-Z_][a-zA-Z0-9_]{2,30}$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
# Regular expression matching correct function names
function-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_,log,cfg,id
# Include a hint for the correct naming format with invalid-name
include-naming-hint=no
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct method names
method-rgx=(([a-z][a-zA-Z0-9_]{2,30})|(_[a-z0-9_]*))$
# Regular expression matching correct module names
#module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
module-rgx=([a-z_][a-z0-9_]*)$
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty
# Regular expression matching correct variable names
variable-rgx=([a-zA-Z0-9_]*)$
[FORMAT]
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Maximum number of characters on a single line.
max-line-length=120
# Maximum number of lines in a module
max-module-lines=2000
# Allow the body of a class to be on the same line as the declaration if body
# contains single statement.No config file found, using default configuration
single-line-class-stmt=no
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[SIMILARITIES]
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
# Minimum lines number of a similarity.
min-similarity-lines=4
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference
# can return multiple potential results while evaluating a Python object, but
# some branches might not be evaluated, which results in partial inference. In
# that case, it might be useful to still emit no-member and other checks for
# the rest of the inferred objects.
ignore-on-opaque-inference=yes
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.
missing-member-hint=yes
# The minimum edit distance a name should have in order to be considered a
# similar match for a missing member name.
missing-member-hint-distance=1
# The total number of similar names that should be taken in consideration when
# showing a hint for a missing member.
missing-member-max-choices=1
[VARIABLES]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables=yes
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*|^ignored_|^unused_
# Tells whether we should check for unused import in __init__ files.
init-import=yes
# List of qualified module names which can have objects that can redefine
# builtins.
redefining-builtins-modules=six.moves,future.builtins
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
[DESIGN]
# Maximum number of arguments for function / method
max-args=8
max-positional-arguments=14
# Maximum number of attributes for a class (see R0902).
max-attributes=20
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of locals for function / method body
max-locals=20
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of statements in function / method body
max-statements=50
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
[IMPORTS]
# Allow wildcard imports from modules that define __all__.
allow-wildcard-with-all=no
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse,tkinter.tix
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=builtins.Exception
================================================
FILE: .vscode/launch.json
================================================
{
// See https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "SearXNG",
"type": "python",
"request": "launch",
"module": "searx.webapp",
"env": {
"FLASK_APP": "webapp",
"FLASK_DEBUG": "1",
"SEARXNG_DEBUG": "1",
},
"args": [
"run"
],
"jinja": true,
"justMyCode": true,
"python": "${workspaceFolder}/local/py3/bin/python",
}
]
}
================================================
FILE: .vscode/settings.json
================================================
{
"python.testing.unittestArgs": [
"-v",
"-s",
"./tests",
"-p",
"test_*.py"
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true,
}
================================================
FILE: .vscode/tasks.json
================================================
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "make run",
"type": "shell",
"command": "make run",
"problemMatcher": [],
"isBackground": true,
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "make docs.live",
"type": "shell",
"command": "make docs.live",
"problemMatcher": [],
"isBackground": true,
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"group": {
"kind": "build"
}
}
]
}
================================================
FILE: .weblate
================================================
[weblate]
url = https://translate.codeberg.org/api/
translation = searxng/searxng
================================================
FILE: .yamllint.yml
================================================
extends: default
rules:
indentation:
spaces: 2
# 120 chars should be enough, but don't fail if a line is longer
line-length:
max: 120
level: warning
allow-non-breakable-words: true
# we don't have multiple document per file
document-start: disable
document-end: disable
================================================
FILE: AI_POLICY.rst
================================================
.. SPDX-License-Identifier: AGPL-3.0-or-later
AI Policy
=========
Restrictions on Generative AI Usage
-----------------------------------
- **All AI usage in any form must be disclosed.** You must state the tool you used (e.g. Claude Code, Cursor, Amp) along with the extent that the work was AI-assisted.
- **The human-in-the-loop must fully understand all code.** If you use generative AI tools as an aid in developing code or documentation changes, ensure that you fully understand the proposed changes and can explain why they are the correct approach.
- **AI should never be the main author of the PR.** AI may be used as a tool to help with developing, but the human contribution to the code changes should always be reasonably larger than the part written by AI. For example, you should be the one that decides about the structure of the PR, not the LLM.
- **Issues and PR descriptions must be fully human-written.** Do not post output from Large Language Models or similar generative AI as comments on any of our discussion forums (e.g. GitHub Issues, Matrix, ...), as such comments tend to be formulaic and low content. If you're a not a native English speaker, using AI for translating self-written issue texts to English is okay, but please keep the wording as close as possible to the original wording.
- **Bad AI drivers will be denounced.** People who produce bad contributions that are clearly AI (slop) will be blocked for all future contributions.
There are Humans Here
---------------------
Every discussion, issue, and pull request is read and reviewed by humans. It is a boundary point at which people interact with each other and the work done. It is rude and disrespectful to approach this boundary with low-effort, unqualified work, since it puts the burden of validation on the maintainer.
It takes a lot of maintainer time and energy to review AI-generated contributions! Sending the output of an LLM to open source project maintainers extracts work from them in the form of design and code review, so we call this kind of contribution an "extractive contribution".
The *golden rule* is that a contribution should be worth more to the project than the time it takes to review it, which is usually not the case if large parts of your PR were written by LLMs.
================================================
FILE: AUTHORS.rst
================================================
searxng is a fork from `searx <https://github.com/searx/searx>`_ and is
maintained by Markus Heiser (`@return42 <https://github.com/return42>`_)
People who have submitted patches/translations, reported bugs, consulted
features or generally made SearXNG better:
- Adam Tauber `@asciimoo <https://github.com/asciimoo>`_
- Matej Cotman `@matejc <https://github.com/matejc>`_
- Émilien Devos `@unixfox <https://github.com/unixfox>`_
- Thomas Pointhuber `pointhi <https://github.com/pointhi>`_
- Noémi Ványi `@kvch <https://github.com/kvch>`_
- `@Cqoicebordel <https://github.com/Cqoicebordel>`_
- Marc Abonce Seguin `@MarcAbonce <https://github.com/MarcAbonce>`_
- `@pofilo <https://github.com/pofilo>`_
- Laszlo Hammerl
- Stefan Marsiske
- Gabor Nagy
- @pw3t
- @rhapsodhy
- András Veres-Szentkirályi
- Benjamin Sonntag
- @HLFH
- @TheRadialActive
- @Okhin
- André Koot
- Alejandro León Aznar
- rike
- dp
- Martin Zimmermann
- @courgette
- @kernc
- @Reventl0v
- Caner Başaran
- Benjamin Sonntag
- @opi
- @dimqua
- Giorgos Logiotatidis
- Luc Didry
- Niklas Haas
- @underr
- Emmanuel Benazera
- @GreenLunar
- Kang-min Liu
- Kirill Isakov
- Guilhem Bonnefille
- @jibe-b
- Christian Pietsch @pietsch
- @Maxqia
- Ashutosh Das @pyprism
- YuLun Shih @imZack
- Dmitry Mikhirev @mikhirev
- David A Roberts `@davidar <https://github.com/davidar>`_
- Jan Verbeek @blyxxyz
- Ammar Najjar @ammarnajjar
- @stepshal
- François Revol @mmuman
- Harry Wood @harry-wood
- Thomas Renard @threnard
- Pydo `<https://github.com/pydo>`_
- Athemis `<https://github.com/Athemis>`_
- Stefan Antoni `<http://stefan.antoni.io>`
- @firebovine
- Lorenzo J. Lucchini @luccoj
- @eig8phei
- @maxigas
- Jannik Winkel @kiney
- @juanitobananas
- Vache Asatryan @vachi
- Luca CPZ @lcpz
- @nikaiw
- Thirnearez
- Hypolite Petovan @MrPetovan
- @woorst
- @Apply55gx
- @pyrrh0n1c
- @cclauss
- QGW @moon2l
- Pierre-Alain Toret @daftaupe
- Matthew Olmsted @icegiant
- Michael Tran @trankmichael
- Joseph Nuthalapati @josephkiranbabu
- @maiki
- Richard Didier @zeph33
- Michael Vieria @Themimitoof
- Richard Nespithal @rndevfx
- Stanislas @angristan
- @rinpatch
- g. s. @usernameisntallowed
- Léo Bourrel @bourrel
- @cy8aer
- @Popolon
- Alice Ferrazzi @aliceinwire
- @LiquidLemon
- @dadosch
- Václav Zouzalík @Venca24
- @ZEROF
- Ivan Skytte Jørgensen @isj-privacore
- @miicha
- Étienne Deparis @milouse
- @pelag0s
- Denis Wernert @d-tux
- Robin Hallabro-Kokko @hallabro
- Jonas Zohren @jfowl
- Elias Ojala @theel0ja
- @brunob
- Nick Espig @nachtalb
- Rachmadani Haryono @rachmadaniHaryono
- Frank de Lange @yetangitu
- Nicolas Gelot @nfk
- @volth
- Mathieu Brunot @madmath03
- @lorddavidiii
- @x250
- Robby O'Connor @robbyoconnor
- Finn @0xhtml
- @tmikaeld
- @hobbestigrou
- Vipul @finn0
- @CaffeinatedTech
- Robin Schneider @ypid
- @splintah
- Lukas van den Berk @lukasvdberk
- @piplongrun
- Jason Kaltsikis @jjasonkal
- Sion Kazama @KazamaSion
- @resynth1943
- Mostafa Ahangarha @ahangarha
- @gordon-quad
- Sophie Tauchert @999eagle
- @bauruine
- Michael Ilsaas `<https://mikeri.net>`_
- @renyhp
- rachmadani haryono @rachmadaniHaryono
- Mohamad Safadieh @msafadieh
- @gardouille
- @resynth1943
- @Eliesemoule
- @gardouille
- @GazoilKerozen
- Lukáš Kucharczyk @KucharczykL
- Lynda Lopez @lyndalopez544
- M. Efe Çetin @efectn
- Nícholas Kegler @nicholasks
- @pierrechtux
- Scott Wallace @scottwallacesh
- @Singustromo
- @TheEvilSkeleton
- @Wonderfall
- @mrwormo
- Xiaoyu WEI @xywei
- @joshu9h
- Daniel Hones
- @cyclaero
- @thezeroalpha
- @Tobi823
- @archiecodes
- @BBaoVanC
- @datagram1
- @lucky13820
- @jhigginbotham
- @xenrox
- @OliveiraHermogenes
- Paul Alcock @Guilvareux
- Sam A. `<https://samsapti.dev>`_
- @XavierHorwood
- Ahmad Alkadri `<https://github.com/ahmad-alkadri>`_
- Milad Laly @Milad-Laly
- @llmII
- @blob42 `<https://blob42.xyz>`_
- Paolo Basso `<https://github.com/paolobasso99>`
- Bernie Huang `<https://github.com/BernieHuang2008>`
- Austin Olacsi `<https://github.com/Austin-Olacsi>`
- @micsthepick
- Daniel Kukula `<https://github.com/dkuku>`
- Patrick Evans `https://github.com/holysoles`
- Daniel Mowitz `<https://daniel.mowitz.rocks>`
- `Bearz314 <https://github.com/bearz314>`_
- Tommaso Colella `<https://github.com/gioleppe>`
- @AgentScrubbles
- Filip Mikina `<https://github.com/fiffek>`
================================================
FILE: CHANGELOG.rst
================================================
=======
SearXNG
=======
SearXNG development has been started in the middle of 2021 as a fork of the
searx project. Since it beginning its a rolling release pulled from SearXNG's
master branch:
- The CHANGELOG_ is replaced by the commit history of the master branch.
- Since merged PR-229_, the version number is based on the git commit
.. _CHANGELOG: https://github.com/searxng/searxng/commits/master
.. _PR-229: https://github.com/searxng/searxng/pull/229
================================================
FILE: CONTRIBUTING.rst
================================================
.. SPDX-License-Identifier: AGPL-3.0-or-later
.. _Quickstart guide: https://docs.searxng.org/dev/quickstart.html
.. _Commits guide: https://docs.searxng.org/dev/commits.html
.. _AI Policy: https://github.com/searxng/searxng/blob/master/AI_POLICY.rst
.. _Weblate: https://translate.codeberg.org/projects/searxng/searxng/
.. _GitHub Codespaces: https://docs.github.com/en/codespaces/overview
.. _120 hours per month: https://github.com/settings/billing
.. _list of existing Codespaces: https://github.com/codespaces
Thank you for your interest in SearXNG.
Have a look at our `Quickstart guide`_, it's very easy to contribute.
Further information on *how-to* can be found
`here <https://docs.searxng.org/dev/index.html>`_.
Translations
============
Help translate SearXNG at `Weblate`_.
.. image:: https://translate.codeberg.org/widget/searxng/searxng/horizontal-auto.svg
:target: https://translate.codeberg.org/engage/searxng/
:alt: Weblate
:width: 768px
Cloud development
=================
You can contribute from your browser using `GitHub Codespaces`_:
- Fork the repository.
- Click on the ``<> Code`` green button.
- Click on the ``Codespaces`` tab instead of ``Local``.
- Click on ``Create codespace on master``.
- VSCode is going to start in the browser.
- Wait for ``git pull && make install`` to appear and then disappear.
- You have `120 hours per month`_ (see also your `list of existing Codespaces`_).
- You can start SearXNG using ``make run`` in the terminal or by pressing ``Ctrl+Shift+B``.
How-to contribute
=================
Submitting pull requests
------------------------
Please follow the provided PR template when writing a description for your
changes.
Do not take criticism personally. When you get feedback, it is about your work,
not your character or personality. Keep in mind we all want to make SearXNG
better.
When something is not clear, please ask questions to clear things up.
If you would like to introduce a big architectural change or do a refactor,
either in the codebase or the development tooling, please open an issue with a
proposal first. This way we can think together about the problem and probably
come up with a better solution.
Coding conventions and guidelines
---------------------------------
Commit messages
~~~~~~~~~~~~~~~
- Always write descriptive commit messages *("fix bug" is not acceptable)*.
- Use the present tense *("Add feature", not "Added feature")*.
- Use the imperative mood *("Move cursor to...", not "Moves cursor to...")*.
- Limit the first line (commit title) to 72 characters or less.
See `Commits guide`_ for more details.
Coding guidelines
~~~~~~~~~~~~~~~~~
As a Python project, we must follow `PEP 8 <https://www.python.org/dev/peps/pep-0008/>`_
and `PEP 20 <https://www.python.org/dev/peps/pep-0020/>`_ guidelines.
Furthermore, follow Clean Code conventions. The most important
rules in this project are:
- Simpler is better. `KISS principle <https://en.wikipedia.org/wiki/KISS_principle>`_
- Be consistent.
- Every function must do one thing.
- Use descriptive names for functions and variables.
- Always look for the root cause.
- Keep configurable data high level.
- Avoid negative conditionals.
- Prefer fewer arguments.
- Do not add obvious comments to code.
- Do not comment out code, delete lines instead.
AI Policy
~~~~~~~~~
For our policy on the use of AI tools, please read `AI Policy`_.
================================================
FILE: LICENSE
================================================
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.
================================================
FILE: Makefile
================================================
# -*- coding: utf-8; mode: makefile-gmake -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
.DEFAULT_GOAL=help
export MTOOLS=./manage
include utils/makefile.include
all: clean install
PHONY += help
help:
@./manage --help
@echo '----'
@echo 'run - run developer instance'
@echo 'install - developer install of SearxNG into virtualenv'
@echo 'uninstall - uninstall developer installation'
@echo 'clean - clean up working tree'
@echo 'test - run shell & CI tests'
@echo 'test.shell - test shell scripts'
@echo 'ci.test - run CI tests'
PHONY += run
run: install
$(Q)./manage webapp.run
PHONY += install uninstall
install uninstall:
$(Q)./manage pyenv.$@
PHONY += clean
clean: py.clean docs.clean node.clean nvm.clean go.clean test.clean
$(Q)./manage build_msg CLEAN "common files"
$(Q)find . -name '*.orig' -exec rm -f {} +
$(Q)find . -name '*.rej' -exec rm -f {} +
$(Q)find . -name '*~' -exec rm -f {} +
$(Q)find . -name '*.bak' -exec rm -f {} +
PHONY += test ci.test test.shell
test: test.yamllint test.black test.pyright_modified test.pylint test.unit test.robot test.rst test.shell test.shfmt
ci.test: test test.pybabel
test.shell:
$(Q)shellcheck -x -s dash \
container/entrypoint.sh
$(Q)shellcheck -x -s bash \
utils/brand.sh \
$(MTOOLS) \
utils/lib.sh \
utils/lib_sxng*.sh \
utils/lib_govm.sh \
utils/lib_nvm.sh \
utils/lib_redis.sh \
utils/lib_valkey.sh \
utils/searxng.sh
$(Q)$(MTOOLS) build_msg TEST "$@ OK"
PHONY += format
format: format.python format.shell
# wrap ./manage script
MANAGE += weblate.translations.commit weblate.push.translations
MANAGE += data.all data.traits data.useragents data.gsa_useragents data.locales data.currencies
MANAGE += docs.html docs.live docs.gh-pages docs.prebuild docs.clean
MANAGE += podman.build
MANAGE += docker.build docker.buildx
MANAGE += container.build container.test container.push
MANAGE += gecko.driver
MANAGE += node.env node.env.dev node.clean
MANAGE += py.build py.clean
MANAGE += pyenv pyenv.install pyenv.uninstall
MANAGE += format.python format.shell
MANAGE += test.yamllint test.pylint test.black test.pybabel test.unit test.coverage test.robot test.rst test.clean test.themes test.pyright test.pyright_modified test.shfmt
MANAGE += themes.all themes.simple themes.simple.analyze themes.fix themes.lint themes.test
MANAGE += static.build.commit static.build.drop static.build.restore
MANAGE += nvm.install nvm.clean nvm.status nvm.nodejs
MANAGE += go.env.dev go.clean
PHONY += $(MANAGE)
$(MANAGE):
$(Q)$(MTOOLS) $@
# short hands of selected targets
PHONY += docs container themes
docs: docs.html
container: container.build
themes: themes.all
================================================
FILE: PULL_REQUEST_TEMPLATE.md
================================================
<!-- FILL IN THESE FIELDS .. and delete the comments after reading.
Use Markdown for formatting -> https://www.markdowntools.io/cheat-sheet
-->
### What does this PR do?
<!-- Explain the motivation and changes in your pull request. -->
### How to test this PR locally?
<!-- Commands to run the tests or instructions to test the changes. Are there
any edge cases (environment, language, or other contexts) to take into
account? -->
### Related issues
<!--
Closes: #234
-->
### Code of Conduct
<!-- ⚠️ Bad AI drivers will be denounced: People who produce bad contributions
that are clearly AI (slop) will be blocked for all future contributions.
-->
[AI Policy]: https://github.com/searxng/searxng/blob/master/AI_POLICY.rst
- [ ] **I hereby confirm that this PR conforms with the [AI Policy].**
If I have used AI tools for working on the changes in this PR, I will
attach a list of all AI tools I used and how I used them. I hereby confirm
that I haven't used any other tools than the ones I mention below.
================================================
FILE: README.rst
================================================
.. SPDX-License-Identifier: AGPL-3.0-or-later
.. _metasearch engine: https://en.wikipedia.org/wiki/Metasearch_engine
.. _Installation guide: https://docs.searxng.org/admin/installation.html
.. _Configuration guide: https://docs.searxng.org/admin/settings/index.html
.. _CONTRIBUTING: https://github.com/searxng/searxng/blob/master/CONTRIBUTING.rst
.. _LICENSE: https://github.com/searxng/searxng/blob/master/LICENSE
.. figure:: https://raw.githubusercontent.com/searxng/searxng/master/client/simple/src/brand/searxng.svg
:target: https://searxng.org
:alt: SearXNG
:width: 512px
SearXNG is a `metasearch engine`_. Users are neither tracked nor profiled.
.. image:: https://img.shields.io/badge/organization-3050ff?style=flat-square&logo=searxng&logoColor=fff&cacheSeconds=86400
:target: https://github.com/searxng
:alt: Organization
.. image:: https://img.shields.io/badge/documentation-3050ff?style=flat-square&logo=readthedocs&logoColor=fff&cacheSeconds=86400
:target: https://docs.searxng.org
:alt: Documentation
.. image:: https://img.shields.io/github/license/searxng/searxng?style=flat-square&label=license&color=3050ff&cacheSeconds=86400
:target: https://github.com/searxng/searxng/blob/master/LICENSE
:alt: License
.. image:: https://img.shields.io/github/commit-activity/y/searxng/searxng/master?style=flat-square&label=commits&color=3050ff&cacheSeconds=3600
:target: https://github.com/searxng/searxng/commits/master/
:alt: Commits
.. image:: https://img.shields.io/weblate/progress/searxng?server=https%3A%2F%2Ftranslate.codeberg.org&style=flat-square&label=translated&color=3050ff&cacheSeconds=86400
:target: https://translate.codeberg.org/projects/searxng/
:alt: Translated
Setup
=====
To install SearXNG, see `Installation guide`_.
To fine-tune SearXNG, see `Configuration guide`_.
Further information on *how-to* can be found `here <https://docs.searxng.org/admin/index.html>`_.
Connect
=======
If you have questions or want to connect with others in the community:
- `#searxng:matrix.org <https://matrix.to/#/#searxng:matrix.org>`_
Contributing
============
See CONTRIBUTING_ for more details.
License
=======
This project is licensed under the GNU Affero General Public License (AGPL-3.0).
See LICENSE_ for more details.
================================================
FILE: SECURITY.md
================================================
# Security Policy
We love responsible reports of (potential) security issues in SearXNG.
You can contact us at security@searxng.org.
Be sure to provide as much information as possible and if found
also reproduction steps of the identified vulnerability. Also
add the specific URL of the project as well as code you found
the issue in to your report.
================================================
FILE: babel.cfg
================================================
[extractors]
searxng_msg = searx.babel_extract.extract
[ignore: **/node_modules/**]
[python: **.py]
[jinja2: **/templates/**.html]
[searxng_msg: **/searxng.msg]
================================================
FILE: client/simple/.gitignore
================================================
dist
node_modules
================================================
FILE: client/simple/.stylelintrc.json
================================================
{
"$schema": "https://json.schemastore.org/stylelintrc.json",
"plugins": ["stylelint-prettier"],
"extends": ["stylelint-config-standard-less"],
"rules": {
"at-rule-no-vendor-prefix": null,
"at-rule-prelude-no-invalid": null,
"declaration-empty-line-before": null,
"declaration-property-value-no-unknown": null,
"no-invalid-position-at-import-rule": null,
"prettier/prettier": true,
"property-no-vendor-prefix": null,
"selector-attribute-quotes": null,
"selector-class-pattern": null,
"selector-id-pattern": null,
"selector-no-vendor-prefix": null,
"shorthand-property-no-redundant-values": null
}
}
================================================
FILE: client/simple/README.rst
================================================
=====================
MEMO vite development
=====================
Local install::
# in folder ./client/simple/
$ npm install
Start development server::
$ ./manage vite.simple.dev
# in folder ./client/simple/
$ npm exec -- vite
Fix source code::
# in folder ./client/simple/
$ npm run fix
Fix & Build::
$ ./manage vite.simple.build
================================================
FILE: client/simple/biome.json
================================================
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"files": {
"ignoreUnknown": true,
"includes": ["**", "!node_modules"]
},
"assist": {
"enabled": true,
"actions": {
"recommended": true,
"source": {
"useSortedAttributes": "on",
"useSortedProperties": "on"
}
}
},
"formatter": {
"enabled": true,
"bracketSameLine": false,
"bracketSpacing": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 120
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": {
"noForEach": "error",
"noImplicitCoercions": "error",
"noUselessCatchBinding": "error",
"noUselessUndefined": "error",
"useSimplifiedLogicExpression": "error"
},
"correctness": {
"noGlobalDirnameFilename": "error",
"useImportExtensions": "error",
"useJsonImportAttributes": "error",
"useSingleJsDocAsterisk": "error"
},
"nursery": {
"noContinue": "warn",
"noEqualsToNull": "warn",
"noFloatingPromises": "warn",
"noForIn": "warn",
"noIncrementDecrement": "warn",
"noMisusedPromises": "warn",
"noMultiAssign": "warn",
"noMultiStr": "warn",
"noNestedPromises": "warn",
"noParametersOnlyUsedInRecursion": "warn",
"noRedundantDefaultExport": "warn",
"noReturnAssign": "warn",
"noUselessReturn": "off",
"useAwaitThenable": "off",
"useConsistentEnumValueType": "warn",
"useDestructuring": "warn",
"useExhaustiveSwitchCases": "warn",
"useExplicitType": "off",
"useFind": "warn",
"useRegexpExec": "warn"
},
"performance": {
"noAwaitInLoops": "error",
"noBarrelFile": "error",
"noDelete": "error",
"noNamespaceImport": "error",
"noReExportAll": "error",
"useTopLevelRegex": "error"
},
"style": {
"noCommonJs": "error",
"noEnum": "error",
"noImplicitBoolean": "error",
"noInferrableTypes": "error",
"noNamespace": "error",
"noNegationElse": "error",
"noNestedTernary": "error",
"noParameterAssign": "error",
"noParameterProperties": "error",
"noRestrictedTypes": {
"level": "error",
"options": {
"types": {
"Element": {
"message": "Element is too generic",
"use": "HTMLElement"
}
}
}
},
"noSubstr": "error",
"noUnusedTemplateLiteral": "error",
"noUselessElse": "error",
"noYodaExpression": "error",
"useAsConstAssertion": "error",
"useAtIndex": "error",
"useCollapsedElseIf": "error",
"useCollapsedIf": "error",
"useConsistentArrayType": {
"level": "error",
"options": {
"syntax": "shorthand"
}
},
"useConsistentBuiltinInstantiation": "error",
"useConsistentMemberAccessibility": {
"level": "error",
"options": {
"accessibility": "explicit"
}
},
"useConsistentObjectDefinitions": {
"level": "error",
"options": {
"syntax": "explicit"
}
},
"useConsistentTypeDefinitions": {
"level": "error",
"options": {
"style": "type"
}
},
"useDefaultSwitchClause": "error",
"useExplicitLengthCheck": "error",
"useForOf": "error",
"useGroupedAccessorPairs": "error",
"useNumberNamespace": "error",
"useNumericSeparators": "error",
"useObjectSpread": "error",
"useReadonlyClassProperties": "error",
"useSelfClosingElements": "error",
"useShorthandAssign": "error",
"useSingleVarDeclarator": "error",
"useThrowNewError": "error",
"useThrowOnlyError": "error",
"useTrimStartEnd": "error",
"useUnifiedTypeSignatures": "error"
},
"suspicious": {
"noAlert": "error",
"noBitwiseOperators": "error",
"noConstantBinaryExpressions": "error",
"noDeprecatedImports": "error",
"noEmptyBlockStatements": "error",
"noEvolvingTypes": "error",
"noImportCycles": "error",
"noUnassignedVariables": "error",
"noVar": "error",
"useNumberToFixedDigitsArgument": "error",
"useStaticResponseMethods": "error"
}
}
},
"javascript": {
"formatter": {
"arrowParentheses": "always",
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"quoteStyle": "double",
"semicolons": "always",
"trailingCommas": "none"
}
}
}
================================================
FILE: client/simple/generated/pygments.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
this file is generated automatically by searxng_extra/update/update_pygments.py
using pygments version 2.20.0:
./manage templates.simple.pygments
*/
.code-highlight {
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.hll { background-color: #ffffcc }
.c { color: #3D7B7B; font-style: italic } /* Comment */
.err { border: 1px solid #F00 } /* Error */
.k { color: #008000; font-weight: bold } /* Keyword */
.o { color: #666 } /* Operator */
.ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
.cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
.cp { color: #9C6500 } /* Comment.Preproc */
.cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
.c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
.cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.gd { color: #A00000 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #E40000 } /* Generic.Error */
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
.gi { color: #008400 } /* Generic.Inserted */
.go { color: #717171 } /* Generic.Output */
.gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.gt { color: #04D } /* Generic.Traceback */
.kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.kp { color: #008000 } /* Keyword.Pseudo */
.kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.kt { color: #B00040 } /* Keyword.Type */
.m { color: #666 } /* Literal.Number */
.s { color: #BA2121 } /* Literal.String */
.na { color: #687822 } /* Name.Attribute */
.nb { color: #008000 } /* Name.Builtin */
.nc { color: #00F; font-weight: bold } /* Name.Class */
.no { color: #800 } /* Name.Constant */
.nd { color: #A2F } /* Name.Decorator */
.ni { color: #717171; font-weight: bold } /* Name.Entity */
.ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
.nf { color: #00F } /* Name.Function */
.nl { color: #767600 } /* Name.Label */
.nn { color: #00F; font-weight: bold } /* Name.Namespace */
.nt { color: #008000; font-weight: bold } /* Name.Tag */
.nv { color: #19177C } /* Name.Variable */
.ow { color: #A2F; font-weight: bold } /* Operator.Word */
.w { color: #BBB } /* Text.Whitespace */
.mb { color: #666 } /* Literal.Number.Bin */
.mf { color: #666 } /* Literal.Number.Float */
.mh { color: #666 } /* Literal.Number.Hex */
.mi { color: #666 } /* Literal.Number.Integer */
.mo { color: #666 } /* Literal.Number.Oct */
.sa { color: #BA2121 } /* Literal.String.Affix */
.sb { color: #BA2121 } /* Literal.String.Backtick */
.sc { color: #BA2121 } /* Literal.String.Char */
.dl { color: #BA2121 } /* Literal.String.Delimiter */
.sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.s2 { color: #BA2121 } /* Literal.String.Double */
.se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
.sh { color: #BA2121 } /* Literal.String.Heredoc */
.si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
.sx { color: #008000 } /* Literal.String.Other */
.sr { color: #A45A77 } /* Literal.String.Regex */
.s1 { color: #BA2121 } /* Literal.String.Single */
.ss { color: #19177C } /* Literal.String.Symbol */
.bp { color: #008000 } /* Name.Builtin.Pseudo */
.fm { color: #00F } /* Name.Function.Magic */
.vc { color: #19177C } /* Name.Variable.Class */
.vg { color: #19177C } /* Name.Variable.Global */
.vi { color: #19177C } /* Name.Variable.Instance */
.vm { color: #19177C } /* Name.Variable.Magic */
.il { color: #666 } /* Literal.Number.Integer.Long */
}
.code-highlight-dark(){
.code-highlight {
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.hll { background-color: #49483e }
.c { color: #959077 } /* Comment */
.err { color: #ED007E; background-color: #1E0010 } /* Error */
.esc { color: #F8F8F2 } /* Escape */
.g { color: #F8F8F2 } /* Generic */
.k { color: #66D9EF } /* Keyword */
.l { color: #AE81FF } /* Literal */
.n { color: #F8F8F2 } /* Name */
.o { color: #FF4689 } /* Operator */
.x { color: #F8F8F2 } /* Other */
.p { color: #F8F8F2 } /* Punctuation */
.ch { color: #959077 } /* Comment.Hashbang */
.cm { color: #959077 } /* Comment.Multiline */
.cp { color: #959077 } /* Comment.Preproc */
.cpf { color: #959077 } /* Comment.PreprocFile */
.c1 { color: #959077 } /* Comment.Single */
.cs { color: #959077 } /* Comment.Special */
.gd { color: #FF4689 } /* Generic.Deleted */
.ge { color: #F8F8F2; font-style: italic } /* Generic.Emph */
.ges { color: #F8F8F2; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.gr { color: #F8F8F2 } /* Generic.Error */
.gh { color: #F8F8F2 } /* Generic.Heading */
.gi { color: #A6E22E } /* Generic.Inserted */
.go { color: #66D9EF } /* Generic.Output */
.gp { color: #FF4689; font-weight: bold } /* Generic.Prompt */
.gs { color: #F8F8F2; font-weight: bold } /* Generic.Strong */
.gu { color: #959077 } /* Generic.Subheading */
.gt { color: #F8F8F2 } /* Generic.Traceback */
.kc { color: #66D9EF } /* Keyword.Constant */
.kd { color: #66D9EF } /* Keyword.Declaration */
.kn { color: #FF4689 } /* Keyword.Namespace */
.kp { color: #66D9EF } /* Keyword.Pseudo */
.kr { color: #66D9EF } /* Keyword.Reserved */
.kt { color: #66D9EF } /* Keyword.Type */
.ld { color: #E6DB74 } /* Literal.Date */
.m { color: #AE81FF } /* Literal.Number */
.s { color: #E6DB74 } /* Literal.String */
.na { color: #A6E22E } /* Name.Attribute */
.nb { color: #F8F8F2 } /* Name.Builtin */
.nc { color: #A6E22E } /* Name.Class */
.no { color: #66D9EF } /* Name.Constant */
.nd { color: #A6E22E } /* Name.Decorator */
.ni { color: #F8F8F2 } /* Name.Entity */
.ne { color: #A6E22E } /* Name.Exception */
.nf { color: #A6E22E } /* Name.Function */
.nl { color: #F8F8F2 } /* Name.Label */
.nn { color: #F8F8F2 } /* Name.Namespace */
.nx { color: #A6E22E } /* Name.Other */
.py { color: #F8F8F2 } /* Name.Property */
.nt { color: #FF4689 } /* Name.Tag */
.nv { color: #F8F8F2 } /* Name.Variable */
.ow { color: #FF4689 } /* Operator.Word */
.pm { color: #F8F8F2 } /* Punctuation.Marker */
.w { color: #F8F8F2 } /* Text.Whitespace */
.mb { color: #AE81FF } /* Literal.Number.Bin */
.mf { color: #AE81FF } /* Literal.Number.Float */
.mh { color: #AE81FF } /* Literal.Number.Hex */
.mi { color: #AE81FF } /* Literal.Number.Integer */
.mo { color: #AE81FF } /* Literal.Number.Oct */
.sa { color: #E6DB74 } /* Literal.String.Affix */
.sb { color: #E6DB74 } /* Literal.String.Backtick */
.sc { color: #E6DB74 } /* Literal.String.Char */
.dl { color: #E6DB74 } /* Literal.String.Delimiter */
.sd { color: #E6DB74 } /* Literal.String.Doc */
.s2 { color: #E6DB74 } /* Literal.String.Double */
.se { color: #AE81FF } /* Literal.String.Escape */
.sh { color: #E6DB74 } /* Literal.String.Heredoc */
.si { color: #E6DB74 } /* Literal.String.Interpol */
.sx { color: #E6DB74 } /* Literal.String.Other */
.sr { color: #E6DB74 } /* Literal.String.Regex */
.s1 { color: #E6DB74 } /* Literal.String.Single */
.ss { color: #E6DB74 } /* Literal.String.Symbol */
.bp { color: #F8F8F2 } /* Name.Builtin.Pseudo */
.fm { color: #A6E22E } /* Name.Function.Magic */
.vc { color: #F8F8F2 } /* Name.Variable.Class */
.vg { color: #F8F8F2 } /* Name.Variable.Global */
.vi { color: #F8F8F2 } /* Name.Variable.Instance */
.vm { color: #F8F8F2 } /* Name.Variable.Magic */
.il { color: #AE81FF } /* Literal.Number.Integer.Long */
}
}
================================================
FILE: client/simple/package.json
================================================
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@searxng/theme-simple",
"version": "0.0.0",
"private": true,
"license": "AGPL-3.0",
"type": "module",
"scripts": {
"build": "npm run build:icons && npm run build:vite",
"build:icons": "node theme_icons.ts",
"build:vite": "vite build",
"clean": "rm -Rf node_modules",
"fix": "npm run fix:stylelint && npm run fix:biome && npm run fix:package",
"fix:biome": "biome check --write",
"fix:package": "sort-package-json --quiet",
"fix:stylelint": "stylelint --fix strict 'src/**/*.{scss,sass,less,styl}'",
"lint": "npm run lint:biome && npm run lint:tsc",
"lint:biome": "biome lint",
"lint:tsc": "tsc --noEmit"
},
"browserslist": [
"baseline 2022",
"not dead"
],
"dependencies": {
"ionicons": "^8.0.13",
"normalize.css": "8.0.1",
"ol": "^10.9.0",
"swiped-events": "1.2.0"
},
"devDependencies": {
"@biomejs/biome": "2.4.15",
"@types/node": "^25.8.0",
"browserslist": "^4.28.2",
"browserslist-to-esbuild": "^2.1.1",
"edge.js": "^6.5.0",
"less": "^4.6.4",
"mathjs": "^15.2.0",
"sharp": "~0.34.5",
"sort-package-json": "^3.6.1",
"stylelint": "^17.11.1",
"stylelint-config-standard-less": "^4.1.0",
"stylelint-prettier": "^5.0.3",
"svgo": "^4.0.1",
"typescript": "~6.0.3",
"vite": "^8.0.13",
"vite-bundle-analyzer": "^1.3.8"
}
}
================================================
FILE: client/simple/src/js/Plugin.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
/**
* Base class for client-side plugins.
*
* @remarks
* Handle conditional loading of the plugin in:
*
* - client/simple/src/js/router.ts
*
* @abstract
*/
export abstract class Plugin {
/**
* Plugin name.
*/
protected readonly id: string;
/**
* @remarks
* Don't hold references of this instance outside the class.
*/
protected constructor(id: string) {
this.id = id;
queueMicrotask(() => this.invoke());
}
private async invoke(): Promise<void> {
try {
console.debug(`[PLUGIN] ${this.id}: Running...`);
const result = await this.run();
if (!result) return;
console.debug(`[PLUGIN] ${this.id}: Running post-exec...`);
// @ts-expect-error
void (await this.post(result as NonNullable<Awaited<ReturnType<this["run"]>>>));
} catch (error) {
console.error(`[PLUGIN] ${this.id}:`, error);
} finally {
console.debug(`[PLUGIN] ${this.id}: Done.`);
}
}
/**
* Plugin goes here.
*
* @remarks
* The plugin is already loaded at this point. If you wish to execute
* conditions to exit early, consider moving the logic to:
*
* - client/simple/src/js/router.ts
*
* ...to avoid unnecessarily loading this plugin on the client.
*/
protected abstract run(): Promise<unknown>;
/**
* Post-execution hook.
*
* @remarks
* The hook is only executed if `#run()` returns a truthy value.
*/
// @ts-expect-error
protected abstract post(result: NonNullable<Awaited<ReturnType<this["run"]>>>): Promise<void>;
}
================================================
FILE: client/simple/src/js/index.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
// core
void import.meta.glob(["./*.ts", "./util/**/.ts"], { eager: true });
================================================
FILE: client/simple/src/js/loader.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import type { Plugin } from "./Plugin.ts";
import { type EndpointsKeys, endpoint } from "./toolkit.ts";
type Options =
| {
on: "global";
}
| {
on: "endpoint";
where: EndpointsKeys[];
};
export const load = <T extends Plugin>(instance: () => Promise<T>, options: Options): void => {
if (!check(options)) return;
void instance();
};
const check = (options: Options): boolean => {
// biome-ignore lint/style/useDefaultSwitchClause: options is typed
switch (options.on) {
case "global": {
return true;
}
case "endpoint": {
if (!options.where.includes(endpoint)) {
// not on the expected endpoint
return false;
}
return true;
}
}
};
================================================
FILE: client/simple/src/js/main/autocomplete.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { http, listen, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
const fetchResults = async (qInput: HTMLInputElement, query: string): Promise<void> => {
try {
let res: Response;
if (settings.method === "GET") {
res = await http("GET", `./autocompleter?q=${query}`);
} else {
res = await http("POST", "./autocompleter", { body: new URLSearchParams({ q: query }) });
}
const results = await res.json();
const autocomplete = document.querySelector<HTMLElement>(".autocomplete");
assertElement(autocomplete);
const autocompleteList = document.querySelector<HTMLUListElement>(".autocomplete ul");
assertElement(autocompleteList);
autocomplete.classList.add("open");
autocompleteList.replaceChildren();
// show an error message that no result was found
if (results?.[1]?.length === 0) {
const noItemFoundMessage = Object.assign(document.createElement("li"), {
className: "no-item-found",
textContent: settings.translations?.no_item_found ?? "No results found"
});
autocompleteList.append(noItemFoundMessage);
return;
}
const fragment = new DocumentFragment();
for (const result of results[1]) {
const li = Object.assign(document.createElement("li"), { textContent: result });
listen("mousedown", li, () => {
qInput.value = result;
const form = document.querySelector<HTMLFormElement>("#search");
form?.submit();
});
fragment.append(li);
}
autocompleteList.append(fragment);
} catch (error) {
console.error("Error fetching autocomplete results:", error);
}
};
const qInput = document.getElementById("q") as HTMLInputElement | null;
assertElement(qInput);
let timeoutId: number;
listen("input", qInput, () => {
clearTimeout(timeoutId);
const query = qInput.value;
const minLength = settings.autocomplete_min ?? 2;
if (query.length < minLength) return;
timeoutId = window.setTimeout(async () => {
if (query === qInput.value) {
await fetchResults(qInput, query);
}
}, 300);
});
const autocomplete: HTMLElement | null = document.querySelector<HTMLElement>(".autocomplete");
const autocompleteList: HTMLUListElement | null = document.querySelector<HTMLUListElement>(".autocomplete ul");
if (autocompleteList) {
listen("keydown", qInput, (event: KeyboardEvent) => {
if (event.key === "Escape") {
autocomplete?.classList.remove("open");
}
});
listen("keyup", qInput, (event: KeyboardEvent) => {
const listItems = [...autocompleteList.children] as HTMLElement[];
const currentIndex = listItems.findIndex((item) => item.classList.contains("active"));
let newCurrentIndex = -1;
switch (event.key) {
case "ArrowUp": {
const currentItem = listItems[currentIndex];
if (currentItem && currentIndex >= 0) {
currentItem.classList.remove("active");
}
// we need to add listItems.length to the index calculation here because the JavaScript modulos
// operator doesn't work with negative numbers
newCurrentIndex = (currentIndex - 1 + listItems.length) % listItems.length;
break;
}
case "ArrowDown": {
const currentItem = listItems[currentIndex];
if (currentItem && currentIndex >= 0) {
currentItem.classList.remove("active");
}
newCurrentIndex = (currentIndex + 1) % listItems.length;
break;
}
case "Enter":
if (autocomplete) {
autocomplete.classList.remove("open");
}
break;
default:
break;
}
if (newCurrentIndex !== -1) {
const selectedItem = listItems[newCurrentIndex];
if (selectedItem) {
selectedItem.classList.add("active");
if (!selectedItem.classList.contains("no-item-found")) {
const qInput = document.getElementById("q") as HTMLInputElement | null;
if (qInput) {
qInput.value = selectedItem.textContent ?? "";
}
}
}
}
});
listen("blur", qInput, () => {
autocomplete?.classList.remove("open");
});
listen("focus", qInput, () => {
autocomplete?.classList.add("open");
});
}
================================================
FILE: client/simple/src/js/main/keyboard.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { listen, mutable, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
export type KeyBindingLayout = "default" | "vim";
type KeyBinding = {
key: string;
fun: (event: KeyboardEvent) => void;
des: string;
cat: string;
};
type HighlightResultElement = "down" | "up" | "visible" | "bottom" | "top";
/* common base for layouts */
const baseKeyBinding: Record<string, KeyBinding> = {
Escape: {
key: "ESC",
fun: (event: KeyboardEvent) => removeFocus(event),
des: "remove focus from the focused input",
cat: "Control"
},
c: {
key: "c",
fun: () => copyURLToClipboard(),
des: "copy url of the selected result to the clipboard",
cat: "Results"
},
h: {
key: "h",
fun: () => toggleHelp(keyBindings),
des: "toggle help window",
cat: "Other"
},
i: {
key: "i",
fun: () => searchInputFocus(),
des: "focus on the search input",
cat: "Control"
},
n: {
key: "n",
fun: () => GoToNextPage(),
des: "go to next page",
cat: "Results"
},
o: {
key: "o",
fun: () => openResult(false),
des: "open search result",
cat: "Results"
},
p: {
key: "p",
fun: () => GoToPreviousPage(),
des: "go to previous page",
cat: "Results"
},
r: {
key: "r",
fun: () => reloadPage(),
des: "reload page from the server",
cat: "Control"
},
t: {
key: "t",
fun: () => openResult(true),
des: "open the result in a new tab",
cat: "Results"
}
};
const keyBindingLayouts: Record<KeyBindingLayout, Record<string, KeyBinding>> = {
// SearXNG layout
default: {
ArrowLeft: {
key: "←",
fun: () => highlightResult("up")(),
des: "select previous search result",
cat: "Results"
},
ArrowRight: {
key: "→",
fun: () => highlightResult("down")(),
des: "select next search result",
cat: "Results"
},
...baseKeyBinding
},
// Vim-like keyboard layout
vim: {
b: {
key: "b",
fun: () => scrollPage(-window.innerHeight),
des: "scroll one page up",
cat: "Navigation"
},
d: {
key: "d",
fun: () => scrollPage(window.innerHeight / 2),
des: "scroll half a page down",
cat: "Navigation"
},
f: {
key: "f",
fun: () => scrollPage(window.innerHeight),
des: "scroll one page down",
cat: "Navigation"
},
g: {
key: "g",
fun: () => scrollPageTo(-document.body.scrollHeight, "top"),
des: "scroll to the top of the page",
cat: "Navigation"
},
j: {
key: "j",
fun: () => highlightResult("down")(),
des: "select next search result",
cat: "Results"
},
k: {
key: "k",
fun: () => highlightResult("up")(),
des: "select previous search result",
cat: "Results"
},
u: {
key: "u",
fun: () => scrollPage(-window.innerHeight / 2),
des: "scroll half a page up",
cat: "Navigation"
},
v: {
key: "v",
fun: () => scrollPageTo(document.body.scrollHeight, "bottom"),
des: "scroll to the bottom of the page",
cat: "Navigation"
},
y: {
key: "y",
fun: () => copyURLToClipboard(),
des: "copy url of the selected result to the clipboard",
cat: "Results"
},
...baseKeyBinding
}
};
const keyBindings: Record<string, KeyBinding> =
settings.hotkeys && settings.hotkeys in keyBindingLayouts
? keyBindingLayouts[settings.hotkeys]
: keyBindingLayouts.default;
const isElementInDetail = (element?: HTMLElement): boolean => {
const ancestor = element?.closest(".detail, .result");
return ancestor?.classList.contains("detail") ?? false;
};
const getResultElement = (element?: HTMLElement): HTMLElement | undefined => {
return element?.closest(".result") ?? undefined;
};
const isImageResult = (resultElement?: HTMLElement): boolean => {
return resultElement?.classList.contains("result-images") ?? false;
};
const highlightResult =
(which: HighlightResultElement | HTMLElement) =>
(noScroll?: boolean, keepFocus?: boolean): void => {
let effectiveWhich = which;
let current = document.querySelector<HTMLElement>(".result[data-vim-selected]");
if (!current) {
// no selection : choose the first one
current = document.querySelector<HTMLElement>(".result");
if (!current) {
// no first one : there are no results
return;
}
// replace up/down actions by selecting first one
if (which === "down" || which === "up") {
effectiveWhich = current;
}
}
const results = Array.from(document.querySelectorAll<HTMLElement>(".result"));
let next: HTMLElement | undefined;
if (typeof effectiveWhich === "string") {
switch (effectiveWhich) {
case "visible": {
const top = document.documentElement.scrollTop || document.body.scrollTop;
const bot = top + document.documentElement.clientHeight;
for (const element of results) {
const etop = element.offsetTop;
const ebot = etop + element.clientHeight;
if (ebot <= bot && etop > top) {
next = element;
break;
}
}
break;
}
case "down":
next = results[results.indexOf(current) + 1] || current;
break;
case "up":
next = results[results.indexOf(current) - 1] || current;
break;
case "bottom":
next = results.at(-1);
break;
// biome-ignore lint/complexity/noUselessSwitchCase: fallthrough is intended
case "top":
default:
[next] = results;
}
} else {
next = effectiveWhich;
}
if (next) {
current.removeAttribute("data-vim-selected");
next.setAttribute("data-vim-selected", "true");
if (!keepFocus) {
const link = next.querySelector<HTMLAnchorElement>("h3 a") || next.querySelector<HTMLAnchorElement>("a");
link?.focus();
}
if (!noScroll) {
mutable.scrollPageToSelected?.();
}
}
};
const reloadPage = (): void => {
document.location.reload();
};
const removeFocus = (event: KeyboardEvent): void => {
const target = event.target as HTMLElement;
const tagName = target?.tagName?.toLowerCase();
if (document.activeElement && (tagName === "input" || tagName === "select" || tagName === "textarea")) {
(document.activeElement as HTMLElement).blur();
} else {
mutable.closeDetail?.();
}
};
const pageButtonClick = (css_selector: string): void => {
const button = document.querySelector<HTMLButtonElement>(css_selector);
if (button) {
button.click();
}
};
const GoToNextPage = (): void => {
pageButtonClick('nav#pagination .next_page button[type="submit"]');
};
const GoToPreviousPage = (): void => {
pageButtonClick('nav#pagination .previous_page button[type="submit"]');
};
mutable.scrollPageToSelected = (): void => {
const sel = document.querySelector<HTMLElement>(".result[data-vim-selected]");
if (!sel) return;
const wtop = document.documentElement.scrollTop || document.body.scrollTop;
const height = document.documentElement.clientHeight;
const etop = sel.offsetTop;
const ebot = etop + sel.clientHeight;
const offset = 120;
// first element ?
if (!sel.previousElementSibling && ebot < height) {
// set to the top of page if the first element
// is fully included in the viewport
window.scroll(window.scrollX, 0);
return;
}
if (wtop > etop - offset) {
window.scroll(window.scrollX, etop - offset);
} else {
const wbot = wtop + height;
if (wbot < ebot + offset) {
window.scroll(window.scrollX, ebot - height + offset);
}
}
};
const scrollPage = (amount: number): void => {
window.scrollBy(0, amount);
highlightResult("visible")();
};
const scrollPageTo = (position: number, nav: HighlightResultElement): void => {
window.scrollTo(0, position);
highlightResult(nav)();
};
const searchInputFocus = (): void => {
window.scrollTo(0, 0);
const q = document.querySelector<HTMLInputElement>("#q");
if (q) {
q.focus();
if (q.setSelectionRange) {
const len = q.value.length;
q.setSelectionRange(len, len);
}
}
};
const openResult = (newTab: boolean): void => {
let link = document.querySelector<HTMLAnchorElement>(".result[data-vim-selected] h3 a");
if (!link) {
link = document.querySelector<HTMLAnchorElement>(".result[data-vim-selected] > a");
}
if (!link) return;
const url = link.getAttribute("href");
if (url) {
if (newTab) {
window.open(url);
} else {
window.location.href = url;
}
}
};
const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBinding): void => {
const categories: Record<string, KeyBinding[]> = {};
for (const binding of Object.values(keyBindings)) {
const { cat } = binding;
categories[cat] ??= [];
categories[cat].push(binding);
}
const sortedCategoryKeys = Object.keys(categories).sort(
(a, b) => (categories[b]?.length ?? 0) - (categories[a]?.length ?? 0)
);
let html = '<a href="#" class="close" aria-label="close" title="close">×</a>';
html += "<h3>How to navigate SearXNG with hotkeys</h3>";
html += "<table>";
for (const [i, categoryKey] of sortedCategoryKeys.entries()) {
const bindings = categories[categoryKey];
if (!bindings || bindings.length === 0) continue;
const isFirst = i % 2 === 0;
const isLast = i === sortedCategoryKeys.length - 1;
if (isFirst) {
html += "<tr>";
}
html += "<td>";
html += `<h4>${categoryKey}</h4>`;
html += '<ul class="list-unstyled">';
for (const binding of bindings) {
html += `<li><kbd>${binding.key}</kbd> ${binding.des}</li>`;
}
html += "</ul>";
html += "</td>";
if (!isFirst || isLast) {
html += "</tr>";
}
}
html += "</table>";
divElement.innerHTML = html;
};
const toggleHelp = (keyBindings: typeof baseKeyBinding): void => {
let helpPanel = document.querySelector<HTMLElement>("#vim-hotkeys-help");
if (helpPanel) {
// toggle hidden
helpPanel.classList.toggle("invisible");
} else {
// first call
helpPanel = Object.assign(document.createElement("div"), {
id: "vim-hotkeys-help",
className: "dialog-modal"
});
initHelpContent(helpPanel, keyBindings);
const [body] = document.getElementsByTagName("body");
if (body) {
body.appendChild(helpPanel);
}
}
};
const copyURLToClipboard = async (): Promise<void> => {
const selectedResult = document.querySelector<HTMLElement>(".result[data-vim-selected]");
if (!selectedResult) return;
const resultAnchor = selectedResult.querySelector<HTMLAnchorElement>("a");
assertElement(resultAnchor);
const url = resultAnchor.getAttribute("href");
if (url) {
if (window.isSecureContext) {
await navigator.clipboard.writeText(url);
} else {
const selection = window.getSelection();
if (selection) {
const node = document.createElement("span");
node.textContent = url;
resultAnchor.appendChild(node);
const range = document.createRange();
range.selectNodeContents(node);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("copy");
node.remove();
}
}
}
};
listen("click", ".result", function (this: HTMLElement, event: PointerEvent) {
if (!isElementInDetail(event.target as HTMLElement)) {
highlightResult(this)(true, true);
const resultElement = getResultElement(event.target as HTMLElement);
if (resultElement && isImageResult(resultElement)) {
event.preventDefault();
mutable.selectImage?.(resultElement);
}
}
});
// FIXME: Focus might also trigger Pointer event ^^^
listen(
"focus",
".result a",
(event: FocusEvent) => {
if (!isElementInDetail(event.target as HTMLElement)) {
const resultElement = getResultElement(event.target as HTMLElement);
if (resultElement && !resultElement.hasAttribute("data-vim-selected")) {
highlightResult(resultElement)(true);
}
if (resultElement && isImageResult(resultElement)) {
event.preventDefault();
mutable.selectImage?.(resultElement);
}
}
},
{ capture: true }
);
listen("keydown", document, (event: KeyboardEvent) => {
// check for modifiers so we don't break browser's hotkeys
if (Object.hasOwn(keyBindings, event.key) && !event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) {
const tagName = (event.target as HTMLElement)?.tagName?.toLowerCase();
if (event.key === "Escape") {
keyBindings[event.key]?.fun(event);
} else if (event.target === document.body || tagName === "a" || tagName === "button") {
event.preventDefault();
keyBindings[event.key]?.fun(event);
}
}
});
mutable.selectNext = highlightResult("down");
mutable.selectPrevious = highlightResult("up");
================================================
FILE: client/simple/src/js/main/preferences.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { http, listen, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
let engineDescriptions: Record<string, [string, string]> | undefined;
const loadEngineDescriptions = async (): Promise<void> => {
if (engineDescriptions) return;
try {
const res = await http("GET", "engine_descriptions.json");
engineDescriptions = await res.json();
} catch (error) {
console.error("Error fetching engineDescriptions:", error);
}
if (!engineDescriptions) return;
for (const [engine_name, [description, source]] of Object.entries(engineDescriptions)) {
const elements = document.querySelectorAll<HTMLElement>(`[data-engine-name="${engine_name}"] .engine-description`);
const sourceText = ` (<i>${settings.translations?.Source}: ${source}</i>)`;
for (const element of elements) {
element.innerHTML = description + sourceText;
}
}
};
const toggleEngines = (enable: boolean, engineToggles: NodeListOf<HTMLInputElement>): void => {
for (const engineToggle of engineToggles) {
// check if element visible, so that only engines of the current category are modified
if (engineToggle.offsetParent) {
engineToggle.checked = !enable;
}
}
};
const engineElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>("[data-engine-name]");
for (const engineElement of engineElements) {
listen("mouseenter", engineElement, loadEngineDescriptions);
}
const engineToggles: NodeListOf<HTMLInputElement> = document.querySelectorAll<HTMLInputElement>(
"tbody input[type=checkbox][class~=checkbox-onoff]"
);
const enableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(".enable-all-engines");
for (const engine of enableAllEngines) {
listen("click", engine, () => toggleEngines(true, engineToggles));
}
const disableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(".disable-all-engines");
for (const engine of disableAllEngines) {
listen("click", engine, () => toggleEngines(false, engineToggles));
}
listen("click", "#copy-hash", async function (this: HTMLElement) {
const target = this.parentElement?.querySelector<HTMLPreElement>("pre");
assertElement(target);
if (window.isSecureContext) {
await navigator.clipboard.writeText(target.innerText);
} else {
const selection = window.getSelection();
if (selection) {
const range = document.createRange();
range.selectNodeContents(target);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("copy");
}
}
if (this.dataset.copiedText) {
this.innerText = this.dataset.copiedText;
}
});
================================================
FILE: client/simple/src/js/main/results.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import "../../../node_modules/swiped-events/src/swiped-events.js";
import { listen, mutable, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
let imgTimeoutID: number;
const imageLoader = (resultElement: HTMLElement): void => {
if (imgTimeoutID) clearTimeout(imgTimeoutID);
const imgElement = resultElement.querySelector<HTMLImageElement>(".result-images-source img");
if (!imgElement) return;
// use thumbnail until full image loads
const thumbnail = resultElement.querySelector<HTMLImageElement>(".image_thumbnail");
if (thumbnail) {
if (thumbnail.src === `${settings.theme_static_path}/img/img_load_error.svg`) return;
imgElement.onerror = (): void => {
imgElement.src = thumbnail.src;
};
imgElement.src = thumbnail.src;
}
const imgSource = imgElement.getAttribute("data-src");
if (!imgSource) return;
// unsafe nodejs specific, cast to https://developer.mozilla.org/en-US/docs/Web/API/Window/setTimeout#return_value
// https://github.com/searxng/searxng/pull/5073#discussion_r2265767231
imgTimeoutID = setTimeout(() => {
imgElement.src = imgSource;
imgElement.removeAttribute("data-src");
}, 1000) as unknown as number;
};
const imageThumbnails: NodeListOf<HTMLImageElement> =
document.querySelectorAll<HTMLImageElement>("#urls img.image_thumbnail");
for (const thumbnail of imageThumbnails) {
if (thumbnail.complete && thumbnail.naturalWidth === 0) {
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
}
thumbnail.onerror = (): void => {
thumbnail.src = `${settings.theme_static_path}/img/img_load_error.svg`;
};
}
const copyUrlButton: HTMLButtonElement | null =
document.querySelector<HTMLButtonElement>("#search_url button#copy_url");
copyUrlButton?.style.setProperty("display", "block");
mutable.selectImage = (resultElement: HTMLElement): void => {
// add a class that can be evaluated in the CSS and indicates that the
// detail view is open
const resultsElement = document.getElementById("results");
resultsElement?.classList.add("image-detail-open");
// add a hash to the browser history so that pressing back doesn't return
// to the previous page this allows us to dismiss the image details on
// pressing the back button on mobile devices
window.location.hash = "#image-viewer";
mutable.scrollPageToSelected?.();
// if there is no element given by the caller, stop here
if (!resultElement) return;
imageLoader(resultElement);
};
mutable.closeDetail = (): void => {
const resultsElement = document.getElementById("results");
resultsElement?.classList.remove("image-detail-open");
// remove #image-viewer hash from url by navigating back
if (window.location.hash === "#image-viewer") {
window.history.back();
}
mutable.scrollPageToSelected?.();
};
listen("click", ".btn-collapse", function (this: HTMLElement) {
const btnLabelCollapsed = this.getAttribute("data-btn-text-collapsed");
const btnLabelNotCollapsed = this.getAttribute("data-btn-text-not-collapsed");
const target = this.getAttribute("data-target");
if (!(target && btnLabelCollapsed && btnLabelNotCollapsed)) return;
const targetElement = document.querySelector<HTMLElement>(target);
assertElement(targetElement);
const isCollapsed = this.classList.contains("collapsed");
const newLabel = isCollapsed ? btnLabelNotCollapsed : btnLabelCollapsed;
const oldLabel = isCollapsed ? btnLabelCollapsed : btnLabelNotCollapsed;
this.innerHTML = this.innerHTML.replace(oldLabel, newLabel);
this.classList.toggle("collapsed");
targetElement.classList.toggle("invisible");
});
listen("click", ".media-loader", function (this: HTMLElement) {
const target = this.getAttribute("data-target");
if (!target) return;
const iframeLoad = document.querySelector<HTMLIFrameElement>(`${target} > iframe`);
assertElement(iframeLoad);
const srctest = iframeLoad.getAttribute("src");
if (!srctest) {
const dataSrc = iframeLoad.getAttribute("data-src");
if (dataSrc) {
iframeLoad.setAttribute("src", dataSrc);
}
}
});
listen("click", "#copy_url", async function (this: HTMLElement) {
const target = this.parentElement?.querySelector<HTMLPreElement>("pre");
assertElement(target);
if (window.isSecureContext) {
await navigator.clipboard.writeText(target.innerText);
} else {
const selection = window.getSelection();
if (selection) {
const range = document.createRange();
range.selectNodeContents(target);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand("copy");
}
}
if (this.dataset.copiedText) {
this.innerText = this.dataset.copiedText;
}
});
listen("click", ".result-detail-close", (event: Event) => {
event.preventDefault();
mutable.closeDetail?.();
});
listen("click", ".result-detail-previous", (event: Event) => {
event.preventDefault();
mutable.selectPrevious?.(false);
});
listen("click", ".result-detail-next", (event: Event) => {
event.preventDefault();
mutable.selectNext?.(false);
});
// listen for the back button to be pressed and dismiss the image details when called
window.addEventListener("hashchange", () => {
if (window.location.hash !== "#image-viewer") {
mutable.closeDetail?.();
}
});
const swipeHorizontal: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(".swipe-horizontal");
for (const element of swipeHorizontal) {
listen("swiped-left", element, () => {
mutable.selectNext?.(false);
});
listen("swiped-right", element, () => {
mutable.selectPrevious?.(false);
});
}
window.addEventListener(
"scroll",
() => {
const backToTopElement = document.getElementById("backToTop");
const resultsElement = document.getElementById("results");
if (backToTopElement && resultsElement) {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const isScrolling = scrollTop >= 100;
resultsElement.classList.toggle("scrolling", isScrolling);
}
},
true
);
================================================
FILE: client/simple/src/js/main/search.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { listen } from "../toolkit.ts";
import { getElement } from "../util/getElement.ts";
const searchForm: HTMLFormElement = getElement<HTMLFormElement>("search");
const searchInput: HTMLInputElement = getElement<HTMLInputElement>("q");
const searchReset: HTMLButtonElement = getElement<HTMLButtonElement>("clear_search");
const isMobile: boolean = window.matchMedia("(max-width: 50em)").matches;
const isResultsPage: boolean = document.querySelector("main")?.id === "main_results";
const categoryButtons: HTMLButtonElement[] = Array.from(
document.querySelectorAll<HTMLButtonElement>("#categories_container button.category")
);
if (searchInput.value.length === 0) {
searchReset.classList.add("empty");
}
// focus search input on large screens
if (!(isMobile || isResultsPage)) {
searchInput.focus();
}
// On mobile, move cursor to the end of the input on focus
if (isMobile) {
listen("focus", searchInput, () => {
// Defer cursor move until the next frame to prevent a visual jump
requestAnimationFrame(() => {
const end = searchInput.value.length;
searchInput.setSelectionRange(end, end);
searchInput.scrollLeft = searchInput.scrollWidth;
});
});
}
listen("input", searchInput, () => {
searchReset.classList.toggle("empty", searchInput.value.length === 0);
});
listen("click", searchReset, (event: MouseEvent) => {
event.preventDefault();
searchInput.value = "";
searchInput.focus();
searchReset.classList.add("empty");
});
for (const button of categoryButtons) {
listen("click", button, (event: MouseEvent) => {
if (event.shiftKey) {
event.preventDefault();
button.classList.toggle("selected");
return;
}
// deselect all other categories
for (const categoryButton of categoryButtons) {
categoryButton.classList.toggle("selected", categoryButton === button);
}
});
}
if (document.querySelector("div.search_filters")) {
const safesearchElement = document.getElementById("safesearch");
if (safesearchElement) {
listen("change", safesearchElement, () => searchForm.submit());
}
const timeRangeElement = document.getElementById("time_range");
if (timeRangeElement) {
listen("change", timeRangeElement, () => searchForm.submit());
}
const languageElement = document.getElementById("language");
if (languageElement) {
listen("change", languageElement, () => searchForm.submit());
}
}
// override searchForm submit event
listen("submit", searchForm, (event: Event) => {
event.preventDefault();
if (categoryButtons.length > 0) {
const searchCategories = getElement<HTMLInputElement>("selected-categories");
searchCategories.value = categoryButtons
.filter((button) => button.classList.contains("selected"))
.map((button) => button.name.replace("category_", ""))
.join(",");
}
searchForm.submit();
});
================================================
FILE: client/simple/src/js/plugin/Calculator.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import {
absDependencies,
addDependencies,
create,
divideDependencies,
eDependencies,
evaluateDependencies,
expDependencies,
factorialDependencies,
gcdDependencies,
lcmDependencies,
log1pDependencies,
log2Dependencies,
log10Dependencies,
logDependencies,
modDependencies,
multiplyDependencies,
nthRootDependencies,
piDependencies,
powDependencies,
roundDependencies,
signDependencies,
sqrtDependencies,
subtractDependencies
} from "mathjs/number";
import { Plugin } from "../Plugin.ts";
import { appendAnswerElement } from "../util/appendAnswerElement.ts";
import { getElement } from "../util/getElement.ts";
/**
* Parses and solves mathematical expressions. Can do basic arithmetic and
* evaluate some functions.
*
* @example
* "(3 + 5) / 2" = "4"
* "e ^ 2 + pi" = "10.530648752520442"
* "gcd(48, 18) + lcm(4, 5)" = "26"
*
* @remarks
* Depends on `mathjs` library.
*/
export default class Calculator extends Plugin {
public constructor() {
super("calculator");
}
/**
* @remarks
* Compare bundle size after adding or removing features.
*/
private static readonly math = create({
...absDependencies,
...addDependencies,
...divideDependencies,
...eDependencies,
...evaluateDependencies,
...expDependencies,
...factorialDependencies,
...gcdDependencies,
...lcmDependencies,
...log10Dependencies,
...log1pDependencies,
...log2Dependencies,
...logDependencies,
...modDependencies,
...multiplyDependencies,
...nthRootDependencies,
...piDependencies,
...powDependencies,
...roundDependencies,
...signDependencies,
...sqrtDependencies,
...subtractDependencies
});
protected async run(): Promise<string | undefined> {
const searchInput = getElement<HTMLInputElement>("q");
const node = Calculator.math.parse(searchInput.value);
try {
return `${node.toString()} = ${node.evaluate()}`;
} catch {
// not a compatible math expression
return;
}
}
protected async post(result: string): Promise<void> {
appendAnswerElement(result);
}
}
================================================
FILE: client/simple/src/js/plugin/InfiniteScroll.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { Plugin } from "../Plugin.ts";
import { http, settings } from "../toolkit.ts";
import { assertElement } from "../util/assertElement.ts";
import { getElement } from "../util/getElement.ts";
/**
* Automatically loads the next page when scrolling to bottom of the current page.
*/
export default class InfiniteScroll extends Plugin {
public constructor() {
super("infiniteScroll");
}
protected async run(): Promise<void> {
const resultsElement = getElement<HTMLElement>("results");
const onlyImages: boolean = resultsElement.classList.contains("only_template_images");
const observedSelector = "article.result:last-child";
const spinnerElement = document.createElement("div");
spinnerElement.className = "loader";
const loadNextPage = async (callback: () => void): Promise<void> => {
const searchForm = document.querySelector<HTMLFormElement>("#search");
assertElement(searchForm);
const form = document.querySelector<HTMLFormElement>("#pagination form.next_page");
assertElement(form);
const action = searchForm.getAttribute("action");
if (!action) {
throw new Error("Form action not defined");
}
const paginationElement = document.querySelector<HTMLElement>("#pagination");
assertElement(paginationElement);
paginationElement.replaceChildren(spinnerElement);
try {
const res = await http("POST", action, { body: new FormData(form) });
const nextPage = await res.text();
if (!nextPage) return;
const nextPageDoc = new DOMParser().parseFromString(nextPage, "text/html");
const articleList = nextPageDoc.querySelectorAll<HTMLElement>("#urls article");
const nextPaginationElement = nextPageDoc.querySelector<HTMLElement>("#pagination");
document.querySelector("#pagination")?.remove();
const urlsElement = document.querySelector<HTMLElement>("#urls");
if (!urlsElement) {
throw new Error("URLs element not found");
}
if (articleList.length > 0 && !onlyImages) {
// do not add <hr> element when there are only images
urlsElement.appendChild(document.createElement("hr"));
}
urlsElement.append(...articleList);
if (nextPaginationElement) {
const results = document.querySelector<HTMLElement>("#results");
results?.appendChild(nextPaginationElement);
callback();
}
} catch (error) {
console.error("Error loading next page:", error);
const errorElement = Object.assign(document.createElement("div"), {
textContent: settings.translations?.error_loading_next_page ?? "Error loading next page",
className: "dialog-error"
});
errorElement.setAttribute("role", "alert");
document.querySelector("#pagination")?.replaceChildren(errorElement);
}
};
const intersectionObserveOptions: IntersectionObserverInit = {
rootMargin: "320px"
};
const observer: IntersectionObserver = new IntersectionObserver(async (entries: IntersectionObserverEntry[]) => {
const [paginationEntry] = entries;
if (paginationEntry?.isIntersecting) {
observer.unobserve(paginationEntry.target);
await loadNextPage(() => {
const nextObservedElement = document.querySelector<HTMLElement>(observedSelector);
if (nextObservedElement) {
observer.observe(nextObservedElement);
}
});
}
}, intersectionObserveOptions);
const initialObservedElement: HTMLElement | null = document.querySelector<HTMLElement>(observedSelector);
if (initialObservedElement) {
observer.observe(initialObservedElement);
}
}
protected async post(): Promise<void> {
// noop
}
}
================================================
FILE: client/simple/src/js/plugin/MapView.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import "ol/ol.css";
import { Feature, Map as OlMap, View } from "ol";
import { GeoJSON } from "ol/format";
import { Point } from "ol/geom";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { fromLonLat } from "ol/proj";
import { OSM, Vector as VectorSource } from "ol/source";
import { Circle, Fill, Stroke, Style } from "ol/style";
import { Plugin } from "../Plugin.ts";
/**
* MapView
*/
export default class MapView extends Plugin {
private readonly map: HTMLElement;
public constructor(map: HTMLElement) {
super("mapView");
this.map = map;
}
protected async run(): Promise<void> {
const { leafletTarget: target, mapLon = "0", mapLat = "0", mapGeojson } = this.map.dataset;
const lon = Number.parseFloat(mapLon);
const lat = Number.parseFloat(mapLat);
const view = new View({ maxZoom: 16, enableRotation: false });
const map = new OlMap({
target: target,
layers: [new TileLayer({ source: new OSM({ maxZoom: 16 }) })],
view: view
});
try {
const markerSource = new VectorSource({
features: [
new Feature({
geometry: new Point(fromLonLat([lon, lat]))
})
]
});
const markerLayer = new VectorLayer({
source: markerSource,
style: new Style({
image: new Circle({
radius: 6,
fill: new Fill({ color: "#3050ff" })
})
})
});
map.addLayer(markerLayer);
} catch (error) {
console.error("Failed to create marker layer:", error);
}
if (mapGeojson) {
try {
const geoSource = new VectorSource({
features: new GeoJSON().readFeatures(JSON.parse(mapGeojson), {
dataProjection: "EPSG:4326",
featureProjection: "EPSG:3857"
})
});
const geoLayer = new VectorLayer({
source: geoSource,
style: new Style({
stroke: new Stroke({ color: "#3050ff", width: 2 }),
fill: new Fill({ color: "#3050ff33" })
})
});
map.addLayer(geoLayer);
const geoSourceExtent = geoSource.getExtent();
if (geoSourceExtent) {
view.fit(geoSourceExtent, { padding: [20, 20, 20, 20] });
}
} catch (error) {
console.error("Failed to create GeoJSON layer:", error);
}
}
}
protected async post(): Promise<void> {
// noop
}
}
================================================
FILE: client/simple/src/js/router.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { load } from "./loader.ts";
import { Endpoints, endpoint, listen, ready, settings } from "./toolkit.ts";
ready(() => {
document.documentElement.classList.remove("no-js");
document.documentElement.classList.add("js");
listen("click", ".close", function (this: HTMLElement) {
(this.parentNode as HTMLElement)?.classList.add("invisible");
});
listen("click", ".searxng_init_map", async function (this: HTMLElement, event: Event) {
event.preventDefault();
this.classList.remove("searxng_init_map");
load(() => import("./plugin/MapView.ts").then(({ default: Plugin }) => new Plugin(this)), {
on: "endpoint",
where: [Endpoints.results]
});
});
if (settings.plugins?.includes("infiniteScroll")) {
load(() => import("./plugin/InfiniteScroll.ts").then(({ default: Plugin }) => new Plugin()), {
on: "endpoint",
where: [Endpoints.results]
});
}
if (settings.plugins?.includes("calculator")) {
load(() => import("./plugin/Calculator.ts").then(({ default: Plugin }) => new Plugin()), {
on: "endpoint",
where: [Endpoints.results]
});
}
});
ready(
() => {
void import("./main/keyboard.ts");
void import("./main/search.ts");
if (settings.autocomplete) {
void import("./main/autocomplete.ts");
}
},
{ on: [endpoint === Endpoints.index] }
);
ready(
() => {
void import("./main/keyboard.ts");
void import("./main/results.ts");
void import("./main/search.ts");
if (settings.autocomplete) {
void import("./main/autocomplete.ts");
}
},
{ on: [endpoint === Endpoints.results] }
);
ready(
() => {
void import("./main/preferences.ts");
},
{ on: [endpoint === Endpoints.preferences] }
);
================================================
FILE: client/simple/src/js/toolkit.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import type { KeyBindingLayout } from "./main/keyboard.ts";
// synced with searx/webapp.py get_client_settings
type Settings = {
plugins?: string[];
advanced_search?: boolean;
autocomplete?: string;
autocomplete_min?: number;
doi_resolver?: string;
favicon_resolver?: string;
hotkeys?: KeyBindingLayout;
method?: "GET" | "POST";
query_in_title?: boolean;
results_on_new_tab?: boolean;
safesearch?: 0 | 1 | 2;
search_on_category_select?: boolean;
theme?: string;
theme_static_path?: string;
translations?: Record<string, string>;
url_formatting?: "pretty" | "full" | "host";
};
type HTTPOptions = {
body?: BodyInit;
timeout?: number;
};
type ReadyOptions = {
// all values must be truthy for the callback to be executed
on?: (boolean | undefined)[];
};
export type EndpointsKeys = keyof typeof Endpoints;
export const Endpoints = {
index: "index",
results: "results",
preferences: "preferences",
unknown: "unknown"
} as const;
export const mutable = {
closeDetail: undefined as (() => void) | undefined,
scrollPageToSelected: undefined as (() => void) | undefined,
selectImage: undefined as ((resultElement: HTMLElement) => void) | undefined,
selectNext: undefined as ((openDetailView?: boolean) => void) | undefined,
selectPrevious: undefined as ((openDetailView?: boolean) => void) | undefined
};
const getEndpoint = (): EndpointsKeys => {
const metaEndpoint = document.querySelector('meta[name="endpoint"]')?.getAttribute("content");
if (metaEndpoint && metaEndpoint in Endpoints) {
return metaEndpoint as EndpointsKeys;
}
return Endpoints.unknown;
};
const getSettings = (): Settings => {
const settings = document.querySelector("script[client_settings]")?.getAttribute("client_settings");
if (!settings) return {};
try {
return JSON.parse(atob(settings));
} catch (error) {
console.error("Failed to load client_settings:", error);
return {};
}
};
export const http = async (method: string, url: string | URL, options?: HTTPOptions): Promise<Response> => {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), options?.timeout ?? 30_000);
const res = await fetch(url, {
body: options?.body,
method: method,
signal: controller.signal
}).finally(() => clearTimeout(timeoutId));
if (!res.ok) {
throw new Error(res.statusText);
}
return res;
};
export const listen = <K extends keyof DocumentEventMap, E extends HTMLElement>(
type: string | K,
target: string | Document | E,
listener: (this: E, event: DocumentEventMap[K]) => void | Promise<void>,
options?: AddEventListenerOptions
): void => {
if (typeof target !== "string") {
target.addEventListener(type, listener as EventListener, options);
return;
}
document.addEventListener(
type,
(event: Event) => {
for (const node of event.composedPath()) {
if (node instanceof HTMLElement && node.matches(target)) {
try {
listener.call(node as E, event as DocumentEventMap[K]);
} catch (error) {
console.error(error);
}
break;
}
}
},
options
);
};
export const ready = (callback: () => void, options?: ReadyOptions): void => {
for (const condition of options?.on ?? []) {
if (!condition) {
return;
}
}
if (document.readyState === "loading") {
listen("DOMContentLoaded", document, callback, { once: true });
} else {
callback();
}
};
export const endpoint: EndpointsKeys = getEndpoint();
export const settings: Settings = getSettings();
================================================
FILE: client/simple/src/js/util/appendAnswerElement.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { getElement } from "./getElement.ts";
export const appendAnswerElement = (element: HTMLElement | string | number): void => {
const results = getElement<HTMLDivElement>("results");
// ./searx/templates/elements/answers.html
let answers = getElement<HTMLDivElement>("answers", { assert: false });
if (!answers) {
// what is this?
const answersTitle = document.createElement("h4");
answersTitle.setAttribute("class", "title");
answersTitle.setAttribute("id", "answers-title");
answersTitle.textContent = "Answers : ";
answers = document.createElement("div");
answers.setAttribute("id", "answers");
answers.setAttribute("role", "complementary");
answers.setAttribute("aria-labelledby", "answers-title");
answers.appendChild(answersTitle);
}
if (!(element instanceof HTMLElement)) {
const span = document.createElement("span");
span.innerHTML = element.toString();
// biome-ignore lint/style/noParameterAssign: TODO
element = span;
}
answers.appendChild(element);
results.insertAdjacentElement("afterbegin", answers);
};
================================================
FILE: client/simple/src/js/util/assertElement.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
type AssertElement = <T>(element?: T | null) => asserts element is T;
export const assertElement: AssertElement = <T>(element?: T | null): asserts element is T => {
if (!element) {
throw new Error("DOM element not found");
}
};
================================================
FILE: client/simple/src/js/util/getElement.ts
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
import { assertElement } from "./assertElement.ts";
type Options = {
assert?: boolean;
};
export function getElement<T>(id: string, options?: { assert: true }): T;
export function getElement<T>(id: string, options?: { assert: false }): T | null;
export function getElement<T>(id: string, options: Options = {}): T | null {
options.assert ??= true;
const element = document.getElementById(id) as T | null;
if (options.assert) {
assertElement(element);
}
return element;
}
================================================
FILE: client/simple/src/less/animations.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
.dialog-modal {
animation-name: dialogmodal;
animation-duration: 0.13s;
@keyframes dialogmodal {
0% {
opacity: 0;
}
50% {
opacity: 0.5;
transform: translate(-50%, -50%) scale(1.05);
}
}
}
input.checkbox-onoff[type="checkbox"]::before {
transition: left 0.25s;
}
================================================
FILE: client/simple/src/less/autocomplete.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
.autocomplete {
position: absolute;
width: @search-width;
max-width: calc(100% - 2 * @search-padding-horizontal);
max-height: 0;
overflow-y: hidden;
.ltr-text-align-left();
.rounded-corners;
&:active,
&:focus,
&:hover {
background-color: var(--color-autocomplete-background);
}
&:empty {
display: none;
}
> ul {
list-style-type: none;
margin: 0;
padding: 0;
> li {
cursor: pointer;
padding: 0.5rem 1rem;
&.active,
&:active,
&:focus,
&:hover {
background-color: var(--color-autocomplete-background-hover);
a:active,
a:focus,
a:hover {
text-decoration: none;
}
}
&.locked {
cursor: inherit;
}
}
}
&.open {
display: block;
background-color: var(--color-autocomplete-background);
color: var(--color-autocomplete-font);
max-height: 32rem;
overflow-y: auto;
z-index: 5000;
margin-top: 3.5rem;
border-radius: 0.8rem;
&:empty {
display: none;
}
}
}
@media screen and (max-width: @phone) {
.autocomplete {
> ul > li {
padding: 1rem;
}
}
}
================================================
FILE: client/simple/src/less/definitions.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
/*
* SearXNG, A privacy-respecting, hackable metasearch engine
*
* To change the colors of the site, simple edit this variables
*/
/// Light Theme
:root {
/// Base Colors
--color-base-font: #444;
--color-base-font-rgb: 68, 68, 68;
--color-base-background: #fff;
--color-base-background-mobile: #f2f5f8;
--color-url-font: #334999;
--color-url-visited-font: #9822c3;
/// Header Colors
--color-header-background: #fdfbff;
--color-header-border: #ddd;
/// Footer Colors
--color-footer-background: #fdfbff;
--color-footer-border: #ddd;
/// Sidebar Colors
--color-sidebar-border: #ddd;
--color-sidebar-font: #000;
--color-sidebar-background: #fff;
/// BackToTop Colors
--color-backtotop-font: #444;
--color-backtotop-border: #ddd;
--color-backtotop-background: #fff;
/// Button Colors
--color-btn-background: #3050ff;
--color-btn-font: #fff;
--color-show-btn-background: #bbb;
--color-show-btn-font: #000;
/// Search Input Colors
--color-search-border: #bbb;
--color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%);
--color-search-background: #fff;
--color-search-font: #222;
--color-search-background-hover: #3050ff;
/// Modal Colors
--color-error: #db3434;
--color-error-background: lighten(#db3434, 40%);
--color-warning: #dbba34;
--color-warning-background: lighten(#dbba34, 40%);
--color-success: #42db34;
--color-success-background: lighten(#42db34, 40%);
/// Categories Colors
--color-categories-item-selected-font: #3050ff;
--color-categories-item-border-selected: #3050ff;
/// Autocomplete Colors
--color-autocomplete-font: #000;
--color-autocomplete-border: #bbb;
--color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%);
--color-autocomplete-background: #fff;
--color-autocomplete-background-hover: #e3e3e3;
/// Answer Colors
--color-answer-font: #444; // same as --color-base-font
--color-answer-background: #fff;
// colors of the KeyValue result class
--color-result-keyvalue-col-table: #fdfbff;
--color-result-keyvalue-odd: #fdfbff;
--color-result-keyvalue-even: #fff;
/// Results Colors
--color-result-background: #fff;
--color-result-border: #ddd;
--color-result-url-font: #000;
--color-result-vim-selected: #f7f7f7;
--color-result-vim-arrow: #000bbb;
--color-result-description-highlight-font: #000;
--color-result-link-font: #000bbb;
--color-result-link-font-highlight: #000bbb;
--color-result-link-visited-font: #9822c3;
--color-result-publishdate-font: #777;
--color-result-engines-font: #545454;
--color-result-search-url-border: #ddd;
--color-result-search-url-font: #000;
// Images Colors
--color-result-image-span-font: #444;
--color-result-image-span-font-selected: #fff;
--color-result-image-background: #fff;
/// Settings Colors
--color-settings-tr-hover: #ebebeb;
--color-settings-engine-description-font: #545454;
--color-settings-table-group-background: #0001;
/// Detail modal
--color-result-detail-font: #fff;
--color-result-detail-label-font: lightgray;
--color-result-detail-background: #242424;
--color-result-detail-hr: #555;
--color-result-detail-link: #8af;
--color-result-detail-loader-border: rgb(255 255 255 / 20%);
--color-result-detail-loader-borderleft: rgb(0 0 0 / 0%);
/// Toolkit Colors
--color-toolkit-badge-font: #fff;
--color-toolkit-badge-background: #545454;
--color-toolkit-kbd-font: #fff;
--color-toolkit-kbd-background: #000;
--color-toolkit-dialog-border: #ddd;
--color-toolkit-dialog-background: #fff;
--color-toolkit-tabs-label-border: #fff;
--color-toolkit-tabs-section-border: #ddd;
--color-toolkit-select-background: #e1e1e1;
--color-toolkit-select-border: #ddd;
--color-toolkit-select-background-hover: #bbb;
--color-toolkit-input-text-font: #222;
--color-toolkit-checkbox-onoff-off-background: #ddd;
--color-toolkit-checkbox-onoff-on-background: #ddd;
--color-toolkit-checkbox-onoff-on-mark-background: #3050ff;
--color-toolkit-checkbox-onoff-on-mark-color: #fff;
--color-toolkit-checkbox-onoff-off-mark-background: #aaa;
--color-toolkit-checkbox-onoff-off-mark-color: #fff;
--color-toolkit-checkbox-label-background: #ddd;
--color-toolkit-checkbox-label-border: #ddd;
--color-toolkit-checkbox-input-border: #3050ff;
--color-toolkit-engine-tooltip-border: #ddd;
--color-toolkit-engine-tooltip-background: #fff;
--color-toolkit-loader-border: rgb(0 0 0 / 20%);
--color-toolkit-loader-borderleft: rgb(255 255 255 / 0%);
--color-doc-code: #003;
--color-doc-code-background: #ddeaff;
/// Other misc colors
--color-bar-chart-primary: #5bc0de;
--color-bar-chart-secondary: #deb15b;
--color-image-resolution-background: rgb(0 0 0 / 50%);
--color-image-resolution-font: #fff;
--color-loading-indicator: rgb(255 255 255 / 20%);
--color-loading-indicator-gap: #fff;
--color-line-number: #64708d;
// Favicons Colors
--color-favicon-background-color: #ddd;
--color-favicon-border-color: #ccc;
}
.dark-themes() {
/// Base Colors
--color-base-font: #bbb;
--color-base-font-rgb: 187, 187, 187;
--color-base-background: #222428;
--color-base-background-mobile: #222428;
--color-url-font: #8af;
--color-url-visited-font: #c09cd9;
/// Header Colors
--color-header-background: #1e1e22;
--color-header-border: #333;
/// Footer Colors
--color-footer-background: #1e1e22;
--color-footer-border: #333;
/// Sidebar Colors
--color-sidebar-border: #555;
--color-sidebar-font: #fff;
--color-sidebar-background: #292c34;
/// BackToTop Colors
--color-backtotop-font: #bbb;
--color-backtotop-border: #333;
--color-backtotop-background: #2b2e36;
/// Button Colors
--color-btn-background: #58f;
--color-btn-font: #222;
--color-show-btn-background: #555;
--color-show-btn-font: #fff;
/// Search Input Colors
--color-search-border: #555;
--color-search-shadow: 0 2px 8px rgb(34 38 46 / 25%);
--color-search-background: #2b2e36;
--color-search-font: #fff;
--color-search-background-hover: #58f;
/// Modal Colors
--color-error: #f55b5b;
--color-error-background: darken(#db3434, 40%);
--color-warning: #f1d561;
--color-warning-background: darken(#dbba34, 40%);
--color-success: #79f56e;
--color-success-background: darken(#42db34, 40%);
/// Categories Colors
--color-categories-item-selected-font: #58f;
--color-categories-item-border-selected: #58f;
/// Autocomplete Colors
--color-autocomplete-font: #fff;
--color-autocomplete-border: #555;
--color-autocomplete-shadow: 0 2px 8px rgb(34 38 46 / 25%);
--color-autocomplete-background: #2b2e36;
--color-autocomplete-background-hover: #1e1e22;
/// Answer Colors
--color-answer-font: #bbb; // same as --color-base-font
--color-answer-background: #26292f;
// colors of the KeyValue result class
--color-result-keyvalue-col-table: #1e1e22;
--color-result-keyvalue-odd: #1e1e22;
--color-result-keyvalue-even: #26292f;
/// Results Colors
--color-result-background: #26292f;
--color-result-border: #333;
--color-result-url-font: #fff;
--color-result-vim-selected: #1f1f23cc;
--color-result-vim-arrow: #8af;
--color-result-description-highlight-font: #fff;
--color-result-link-font: #8af;
--color-result-link-font-highlight: #8af;
--color-result-link-visited-font: #c09cd9;
--color-result-publishdate-font: #888;
--color-result-engines-font: #a4a4a4;
--color-result-search-url-border: #555;
--color-result-search-url-font: #fff;
/// Detail modal : same as the light version
--color-result-detail-font: #fff;
--color-result-detail-label-font: lightgray;
--color-result-detail-background: #1a1a1c;
--color-result-detail-hr: #555;
--color-result-detail-link: #8af;
--color-result-detail-loader-border: rgb(255 255 255 / 20%);
--color-result-detail-loader-borderleft: rgb(0 0 0 / 0%);
// Images Colors
--color-result-image-span-font: #bbb;
--color-result-image-span-font-selected: #222;
--color-result-image-background: #222;
/// Settings Colors
--color-settings-tr-hover: #2c2c32;
--color-settings-engine-description-font: darken(#dcdcdc, 30%);
--color-settings-table-group-background: #1b1b21;
/// Toolkit Colors
--color-toolkit-badge-font: #fff;
--color-toolkit-badge-background: #555;
--color-toolkit-kbd-font: #000;
--color-toolkit-kbd-background: #fff;
--color-toolkit-dialog-border: #555;
--color-toolkit-dialog-background: #1e1e22;
--color-toolkit-tabs-label-border: #222;
--color-toolkit-tabs-section-border: #555;
--color-toolkit-select-background: #313338;
--color-toolkit-select-border: #555;
--color-toolkit-select-background-hover: #373b49;
--color-toolkit-input-text-font: #fff;
--color-toolkit-checkbox-onoff-off-background: #313338;
--color-toolkit-checkbox-onoff-on-background: #313338;
--color-toolkit-checkbox-onoff-on-mark-background: #58f;
--color-toolkit-checkbox-onoff-on-mark-color: #222;
--color-toolkit-checkbox-onoff-off-mark-background: #ddd;
--color-toolkit-checkbox-onoff-off-mark-color: #222;
--color-toolkit-checkbox-label-background: #222;
--color-toolkit-checkbox-label-border: #333;
--color-toolkit-checkbox-input-border: #58f;
--color-toolkit-engine-tooltip-border: #333;
--color-toolkit-engine-tooltip-background: #222;
--color-toolkit-loader-border: rgb(255 255 255 / 20%);
--color-toolkit-loader-borderleft: rgb(0 0 0 / 0%);
--color-doc-code: #ddd;
--color-doc-code-background: #4d5a6f;
// Favicons Colors
--color-favicon-background-color: #ddd;
--color-favicon-border-color: #ccc;
}
.black-themes() {
--color-base-background: #000;
--color-base-background-mobile: #000;
--color-header-background: #000;
--color-footer-background: #000;
--color-sidebar-background: #000;
}
/// Dark Theme (autoswitch based on device pref)
@media (prefers-color-scheme: dark) {
:root.theme-auto {
.dark-themes();
}
}
// Dark Theme by preferences
:root.theme-dark {
.dark-themes();
}
:root.theme-black {
.dark-themes();
.black-themes();
}
/// General Size
@results-width: 45rem;
@results-sidebar-width: 25rem;
@results-offset: 10rem;
@results-tablet-offset: 0.5rem;
@results-gap: 5rem;
@results-margin: 0.125rem;
@result-padding: 1rem;
@results-image-row-height: 12rem;
@results-image-row-height-phone: 10rem;
@search-width: 44rem;
// height of #search, see detail.less
@search-height: 13rem;
@search-padding-horizontal: 0.5rem;
/// Device Size
/// @desktop > @tablet
@tablet: 79.75em; // see https://github.com/searxng/searxng/issues/874
@phone: 50em;
@small-phone: 35em;
@ultra-small-phone: 20rem;
/// From style.less
@stacked-bar-chart: rgb(0, 0, 0);
/// Load fonts from this directory.
@icon-font-path: "../../../fonts/";
//** File name for all font files.
@icon-font-name: "glyphicons-halflings-regular";
//** Element ID within SVG icon file.
@icon-font-svg-id: "glyphicons_halflingsregular";
// decoration of the select HTML elements
@select-light-svg-path: "../svg/select-light.svg";
@select-dark-svg-path: "../svg/select-dark.svg";
================================================
FILE: client/simple/src/less/detail.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
#main_results #results.image-detail-open.only_template_images {
width: min(98%, 59.25rem) !important;
}
#main_results #results.only_template_images.image-detail-open #backToTop {
.ltr-left(56.75rem) !important;
.ltr-right(inherit);
}
article.result-images .detail {
display: none;
}
#results.image-detail-open article.result-images[data-vim-selected] .detail {
display: flex;
flex-direction: column;
position: fixed;
.ltr-left(60rem);
.ltr-right(0);
top: @search-height;
transition: top 0.064s ease-in 0s;
bottom: 0;
background: var(--color-result-detail-background);
border: 1px solid var(--color-result-detail-background);
z-index: 1000;
padding: 4rem 3rem 3rem 3rem;
overflow-y: scroll;
a.result-images-source {
display: block;
flex: 1;
text-align: left;
width: 100%;
border: none;
text-decoration: none;
img {
padding: 0;
margin: 0;
border: none;
object-fit: contain;
width: inherit;
height: inherit;
max-width: 100%;
min-height: inherit;
max-height: calc(100vh - 25rem - 17rem);
background: inherit;
}
}
.result-images-labels {
color: var(--color-result-detail-font);
height: 19rem;
hr {
border-top: 1px solid var(--color-result-detail-hr);
border-bottom: none;
}
h4 {
height: 2rem;
overflow: hidden;
text-overflow: ellipsis;
font-size: 0.9rem;
margin-bottom: 0;
}
p {
color: var(--color-result-detail-label-font);
font-size: 0.9rem;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
margin: 0.8rem 0;
span {
display: inline-block;
width: 12rem;
}
}
h4,
p,
a {
.ltr-text-align-left();
}
p.result-content {
height: 2rem;
line-height: unset;
overflow: hidden;
text-overflow: ellipsis;
}
p.result-url {
white-space: nowrap;
overflow: hidden hidden;
text-overflow: ellipsis;
}
p.result-content:hover,
p.result-url:hover {
position: relative;
overflow: inherit !important;
background: var(--color-result-detail-background);
text-overflow: inherit !important;
}
a,
a:visited,
a:hover,
a:active {
color: var(--color-result-detail-link);
}
a:hover {
text-decoration: underline;
}
}
a.result-detail-close {
top: 1rem;
.ltr-left(1rem);
padding: 0.4rem;
}
a.result-detail-previous {
top: 1rem;
.ltr-right(6rem);
// center the icon by moving it slightly on the left
padding-top: 0.4rem;
.ltr-padding-right(0.5rem);
padding-bottom: 0.4rem;
.ltr-padding-left(0.3rem);
}
a.result-detail-next {
top: 1rem;
.ltr-right(2rem);
padding: 0.4rem;
}
a.result-detail-close,
a.result-detail-next,
a.result-detail-previous {
border-radius: 50%;
display: block;
width: 1.5rem;
height: 1.5rem;
position: absolute;
filter: opacity(40%);
z-index: 1200;
span {
display: block;
width: 1.5rem;
height: 1.5rem;
text-align: center;
}
}
a.result-detail-next,
a.result-detail-previous {
span::before {
// vertical center small icons
vertical-align: sub;
}
}
a.result-detail-close,
a.result-detail-close:visited,
a.result-detail-close:hover,
a.result-detail-close:active,
a.result-detail-previous,
a.result-detail-previous:visited,
a.result-detail-previous:hover,
a.result-detail-previous:active,
a.result-detail-next,
a.result-detail-next:visited,
a.result-detail-next:hover,
a.result-detail-next:active {
color: var(--color-result-detail-font);
background: var(--color-result-detail-background);
border: 1px solid var(--color-result-detail-font);
}
a.result-detail-close:focus,
a.result-detail-close:hover,
a.result-detail-previous:focus,
a.result-detail-previous:hover,
a.result-detail-next:focus,
a.result-detail-next:hover {
filter: opacity(80%);
}
.loader {
position: absolute;
top: 1rem;
.ltr-right(50%);
border-top: 0.5em solid var(--color-result-detail-loader-border);
border-right: 0.5em solid var(--color-result-detail-loader-border);
border-bottom: 0.5em solid var(--color-result-detail-loader-border);
border-left: 0.5em solid var(--color-result-detail-loader-borderleft);
}
}
#results.image-detail-open.scrolling
article.result-images[data-vim-selected]
.detail {
top: 0;
a.result-images-source img {
max-height: calc(100vh - 25rem);
}
}
@media screen and (max-width: @tablet) {
#results.image-detail-open article.result-images[data-vim-selected] .detail {
top: 0;
.ltr-left(0);
a.result-images-source {
display: flex;
flex-direction: column;
justify-content: center;
img {
width: 100%;
max-height: calc(100vh - 24rem);
}
}
a.result-detail-next {
.ltr-right(1rem);
}
}
}
@media screen and (max-width: @phone) {
#results.image-detail-open article.result-images[data-vim-selected] .detail {
top: 0;
.ltr-left(0);
padding: 1rem;
a.result-images-source img {
width: 100%;
max-height: calc(100vh - 2rem);
margin: 0;
}
.result-images-labels p span {
width: inherit;
.ltr-margin-right(1rem);
}
}
}
================================================
FILE: client/simple/src/less/embedded.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
iframe[src^="https://w.soundcloud.com"] {
height: 120px;
}
iframe[src^="https://www.deezer.com"] {
// The real size is 92px, but 94px are needed to avoid an inner scrollbar of
// the embedded HTML.
height: 94px;
}
iframe[src^="https://www.mixcloud.com"] {
// the embedded player from mixcloud has some quirks: initial there is an
// issue with an image URL that is blocked since it is an a Cross-Origin
// request. The alternative text (<img alt='Mixcloud Logo'> then cause an
// scrollbar in the inner of the iframe we can't avoid. Another quirk comes
// when pressing the play button, sometimes the shown player has an height of
// 200px, sometimes 250px.
height: 250px;
}
iframe[src^="https://bandcamp.com/EmbeddedPlayer"] {
// show playlist
height: 350px;
}
iframe[src^="https://bandcamp.com/EmbeddedPlayer/track"] {
// hide playlist
height: 120px;
}
iframe[src^="https://genius.com/songs"] {
height: 65px;
}
================================================
FILE: client/simple/src/less/index.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
#main_index {
margin-top: 26vh;
}
.index {
text-align: center;
.title {
background: url("./img/searxng.png") no-repeat;
min-height: 4rem;
margin: 4rem auto;
background-position: center;
background-size: contain;
}
h1 {
font-size: 4em;
visibility: hidden;
}
#search,
#search_header {
margin: 0 auto;
background: inherit;
border: inherit;
padding: 0;
display: block;
}
.search_filters {
display: block;
margin: 1em 0;
}
.category label {
padding: 6px 10px;
border-bottom: initial !important;
}
}
@media screen and (max-width: @tablet) {
div.title {
h1 {
font-size: 1em;
}
}
#main_index {
margin-top: 6em;
}
}
================================================
FILE: client/simple/src/less/info.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
.info-page {
code {
font-family: monospace;
.rounded-corners-tiny;
background-color: var(--color-doc-code-background);
color: var(--color-doc-code);
padding: 0.2rem;
border: 0 none;
}
}
================================================
FILE: client/simple/src/less/mixins.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
// Mixins
.text-size-adjust (@property: 100%) {
text-size-adjust: @property;
}
.rounded-corners (@radius: 10px) {
border-radius: @radius;
}
.rounded-right-corners (@radius: 0 10px 10px 0) {
border-radius: @radius;
}
.rounded-corners-tiny (@radius: 5px) {
border-radius: @radius;
}
// disable user selection
.disable-user-select () {
user-select: none;
}
.show-content-button() {
padding: 5px 10px;
.rounded-corners-tiny;
background: var(--color-show-btn-background);
color: var(--color-show-btn-font);
cursor: pointer;
&:hover {
background: var(--color-btn-background);
color: var(--color-btn-font);
}
}
================================================
FILE: client/simple/src/less/preferences.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
table {
border-collapse: collapse;
th,
td {
text-align: center;
padding: 1rem 0.5rem;
.ltr-text-align-left();
}
tr.pref-group th {
font-weight: normal;
.ltr-text-align-left();
background: var(--color-settings-table-group-background);
}
}
#main_preferences {
form {
width: 100%;
}
fieldset {
margin: 8px;
border: none;
}
legend {
margin: 0;
padding: 5px 0 0 0;
display: block;
.ltr-float-left();
width: 300px;
}
input[type="text"] {
width: 13.25rem;
color: var(--color-toolkit-input-text-font);
border: none;
background: none repeat scroll 0 0 var(--color-toolkit-select-background);
padding: 0.2rem 0.4rem;
height: 2rem;
.rounded-corners-tiny;
&:hover,
&:focus {
background-color: var(--color-toolkit-select-background-hover);
}
}
div.pref-group {
width: 100%;
font-weight: normal;
padding: 1rem 0.5rem;
.ltr-text-align-left();
background: var(--color-settings-table-group-background);
}
.value {
margin: 0;
padding: 0;
.ltr-float-left();
width: 15em;
select,
input[type="text"] {
font-size: inherit !important;
margin-top: 0;
.ltr-margin-right(1rem);
margin-bottom: 0;
.ltr-margin-left(0);
}
select {
width: 14rem;
}
select:focus,
input:focus {
outline: none;
box-shadow: 0 0 1px 1px var(--color-btn-background);
}
}
.description {
margin: 0;
padding: 5px 0 0 0;
.ltr-float-right();
width: 50%;
color: var(--color-settings-engine-description-font);
font-size: 90%;
}
.bang {
.ltr-text-align-left();
.rounded-corners-tiny;
background-color: var(--color-doc-code-background);
color: var(--color-doc-code);
padding: 0.2rem;
border: 0 none;
}
.category {
.ltr-margin-right(0.5rem);
label {
border: 2px solid transparent;
padding: 0.2rem 0.4rem;
.rounded-corners-tiny;
}
}
.category input[type="checkbox"]:checked + label {
border: 2px solid var(--color-categories-item-border-selected);
}
table.table_engines {
th.name {
/* stylelint-disable */
label {
cursor: pointer;
}
/* stylelint-enable */
.engine-tooltip {
margin-top: 1.8rem;
.ltr-left(calc((100% - 85em) / 2 + 10em));
max-width: 40rem;
.engine-description {
margin-top: 0.5rem;
}
.bang {
margin: 0.3rem;
}
}
}
.checkbox-col,
.name,
.shortcut {
.ltr-text-align-left();
}
}
table.cookies {
width: 100%;
direction: ltr;
th,
td {
text-align: left;
font-family: monospace;
font-size: 1rem;
padding: 0.5em;
vertical-align: top;
}
td:first-child {
word-break: keep-all;
width: 14rem;
padding-right: 1rem;
}
td:last-child {
word-break: break-all;
}
& > tbody > tr:nth-child(even) > th,
& > tbody > tr:nth-child(even) > td {
background-color: var(--color-settings-tr-hover);
}
}
.preferences_back {
background: none repeat scroll 0 0 var(--color-btn-background);
color: var(--color-btn-font);
border: 0 none;
.rounded-corners;
cursor: pointer;
display: inline-block;
margin: 2px 4px;
padding: 0.7em;
a {
color: var(--color-settings-return-font);
}
a::first-letter {
text-transform: uppercase;
}
}
#toggle-all-engines-container {
width: max-content;
margin-left: auto;
}
div.selectable_url {
pre {
width: 100%;
}
}
#copy-hash-container {
display: flex;
align-items: center;
gap: 0.5rem;
div.selectable_url {
pre {
width: auto;
flex-grow: 1;
}
}
}
#pref-hash-input {
width: 100%;
}
}
@media screen and (max-width: @tablet) {
.preferences_back {
clear: both;
}
.engine-tooltip {
.ltr-left(10em) !important;
}
}
================================================
FILE: client/simple/src/less/result_templates.less
================================================
// SPDX-License-Identifier: AGPL-3.0-or-later
.osm-map-box {
hei
gitextract_vt94lyrq/
├── .coveragerc
├── .devcontainer/
│ ├── Dockerfile
│ └── devcontainer.json
├── .dir-locals-template.el
├── .dockerignore
├── .editorconfig
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug-report.md
│ │ ├── config.yml
│ │ ├── engine-request.md
│ │ └── feature-request.md
│ ├── dependabot.yml
│ └── workflows/
│ ├── container.yml
│ ├── data-update.yml
│ ├── documentation.yml
│ ├── integration.yml
│ ├── l10n.yml
│ └── security.yml
├── .gitignore
├── .nvmrc
├── .pylintrc
├── .vscode/
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── .weblate
├── .yamllint.yml
├── AI_POLICY.rst
├── AUTHORS.rst
├── CHANGELOG.rst
├── CONTRIBUTING.rst
├── LICENSE
├── Makefile
├── PULL_REQUEST_TEMPLATE.md
├── README.rst
├── SECURITY.md
├── babel.cfg
├── client/
│ └── simple/
│ ├── .gitignore
│ ├── .stylelintrc.json
│ ├── README.rst
│ ├── biome.json
│ ├── generated/
│ │ └── pygments.less
│ ├── package.json
│ ├── src/
│ │ ├── js/
│ │ │ ├── Plugin.ts
│ │ │ ├── index.ts
│ │ │ ├── loader.ts
│ │ │ ├── main/
│ │ │ │ ├── autocomplete.ts
│ │ │ │ ├── keyboard.ts
│ │ │ │ ├── preferences.ts
│ │ │ │ ├── results.ts
│ │ │ │ └── search.ts
│ │ │ ├── plugin/
│ │ │ │ ├── Calculator.ts
│ │ │ │ ├── InfiniteScroll.ts
│ │ │ │ └── MapView.ts
│ │ │ ├── router.ts
│ │ │ ├── toolkit.ts
│ │ │ └── util/
│ │ │ ├── appendAnswerElement.ts
│ │ │ ├── assertElement.ts
│ │ │ └── getElement.ts
│ │ └── less/
│ │ ├── animations.less
│ │ ├── autocomplete.less
│ │ ├── definitions.less
│ │ ├── detail.less
│ │ ├── embedded.less
│ │ ├── index.less
│ │ ├── info.less
│ │ ├── mixins.less
│ │ ├── preferences.less
│ │ ├── result_templates.less
│ │ ├── result_types/
│ │ │ ├── code.less
│ │ │ ├── file.less
│ │ │ ├── keyvalue.less
│ │ │ └── paper.less
│ │ ├── rss.less
│ │ ├── search.less
│ │ ├── stats.less
│ │ ├── style-center.less
│ │ ├── style-ltr.less
│ │ ├── style-rtl.less
│ │ ├── style.less
│ │ ├── toolkit.less
│ │ ├── toolkit_loader.less
│ │ └── weather.less
│ ├── theme_icons.ts
│ ├── tools/
│ │ ├── img.ts
│ │ ├── jinja_svg_catalog.html.edge
│ │ ├── jinja_svg_catalog.ts
│ │ └── plg.ts
│ ├── tsconfig.json
│ └── vite.config.ts
├── container/
│ ├── builder.dockerfile
│ ├── dist.dockerfile
│ ├── docker-compose.yml
│ └── entrypoint.sh
├── docs/
│ ├── _static/
│ │ └── searxng.css
│ ├── admin/
│ │ ├── answer-captcha.rst
│ │ ├── api.rst
│ │ ├── arch_public.dot
│ │ ├── architecture.rst
│ │ ├── buildhosts.rst
│ │ ├── index.rst
│ │ ├── installation-apache.rst
│ │ ├── installation-docker.rst
│ │ ├── installation-granian.rst
│ │ ├── installation-nginx.rst
│ │ ├── installation-scripts.rst
│ │ ├── installation-searxng.rst
│ │ ├── installation-uwsgi.rst
│ │ ├── installation.rst
│ │ ├── plugins.rst
│ │ ├── searx.favicons.rst
│ │ ├── searx.limiter.rst
│ │ ├── settings/
│ │ │ ├── index.rst
│ │ │ ├── settings.rst
│ │ │ ├── settings_brand.rst
│ │ │ ├── settings_categories_as_tabs.rst
│ │ │ ├── settings_engines.rst
│ │ │ ├── settings_general.rst
│ │ │ ├── settings_outgoing.rst
│ │ │ ├── settings_plugins.rst
│ │ │ ├── settings_redis.rst
│ │ │ ├── settings_search.rst
│ │ │ ├── settings_server.rst
│ │ │ ├── settings_ui.rst
│ │ │ └── settings_valkey.rst
│ │ └── update-searxng.rst
│ ├── build-templates/
│ │ └── searxng.rst
│ ├── conf.py
│ ├── dev/
│ │ ├── answerers/
│ │ │ ├── builtins.rst
│ │ │ ├── development.rst
│ │ │ ├── index.rst
│ │ │ ├── random.rst
│ │ │ └── statistics.rst
│ │ ├── commits.rst
│ │ ├── contribution_guide.rst
│ │ ├── csv_table.txt
│ │ ├── engines/
│ │ │ ├── demo/
│ │ │ │ ├── demo_offline.rst
│ │ │ │ └── demo_online.rst
│ │ │ ├── engine_overview.rst
│ │ │ ├── enginelib.rst
│ │ │ ├── engines.rst
│ │ │ ├── index.rst
│ │ │ ├── json_engine.rst
│ │ │ ├── mediawiki.rst
│ │ │ ├── offline/
│ │ │ │ ├── command-line-engines.rst
│ │ │ │ ├── nosql-engines.rst
│ │ │ │ ├── search-indexer-engines.rst
│ │ │ │ └── sql-engines.rst
│ │ │ ├── offline_concept.rst
│ │ │ ├── online/
│ │ │ │ ├── adobe_stock.rst
│ │ │ │ ├── alpinelinux.rst
│ │ │ │ ├── annas_archive.rst
│ │ │ │ ├── aol.rst
│ │ │ │ ├── archlinux.rst
│ │ │ │ ├── arxiv.rst
│ │ │ │ ├── astrophysics_data_system.rst
│ │ │ │ ├── azure.rst
│ │ │ │ ├── bing.rst
│ │ │ │ ├── bpb.rst
│ │ │ │ ├── brave.rst
│ │ │ │ ├── bt4g.rst
│ │ │ │ ├── cara.rst
│ │ │ │ ├── chinaso.rst
│ │ │ │ ├── core.rst
│ │ │ │ ├── crossref.rst
│ │ │ │ ├── dailymotion.rst
│ │ │ │ ├── discourse.rst
│ │ │ │ ├── duckduckgo.rst
│ │ │ │ ├── geizhals.rst
│ │ │ │ ├── gitea.rst
│ │ │ │ ├── github_code.rst
│ │ │ │ ├── gitlab.rst
│ │ │ │ ├── google.rst
│ │ │ │ ├── huggingface.rst
│ │ │ │ ├── karmasearch.rst
│ │ │ │ ├── lemmy.rst
│ │ │ │ ├── loc.rst
│ │ │ │ ├── marginalia.rst
│ │ │ │ ├── mastodon.rst
│ │ │ │ ├── moviepilot.rst
│ │ │ │ ├── mrs.rst
│ │ │ │ ├── mwmbl.rst
│ │ │ │ ├── odysee.rst
│ │ │ │ ├── openalex.rst
│ │ │ │ ├── openlibrary.rst
│ │ │ │ ├── peertube.rst
│ │ │ │ ├── piped.rst
│ │ │ │ ├── presearch.rst
│ │ │ │ ├── pubmed.rst
│ │ │ │ ├── qwant.rst
│ │ │ │ ├── radio_browser.rst
│ │ │ │ ├── recoll.rst
│ │ │ │ ├── repology.rst
│ │ │ │ ├── reuters.rst
│ │ │ │ ├── semantic_scholar.rst
│ │ │ │ ├── soundcloud.rst
│ │ │ │ ├── sourcehut.rst
│ │ │ │ ├── springer.rst
│ │ │ │ ├── startpage.rst
│ │ │ │ ├── tagesschau.rst
│ │ │ │ ├── torznab.rst
│ │ │ │ ├── tubearchivist.rst
│ │ │ │ ├── void.rst
│ │ │ │ ├── wallhaven.rst
│ │ │ │ ├── wikipedia.rst
│ │ │ │ ├── yacy.rst
│ │ │ │ ├── yahoo.rst
│ │ │ │ └── zlibrary.rst
│ │ │ ├── online_url_search/
│ │ │ │ └── tineye.rst
│ │ │ └── xpath.rst
│ │ ├── extended_types.rst
│ │ ├── hello.dot
│ │ ├── index.rst
│ │ ├── makefile.rst
│ │ ├── plugins/
│ │ │ ├── builtins.rst
│ │ │ ├── calculator.rst
│ │ │ ├── development.rst
│ │ │ ├── hash_plugin.rst
│ │ │ ├── hostnames.rst
│ │ │ ├── index.rst
│ │ │ ├── infinite_scroll.rst
│ │ │ ├── self_info.rst
│ │ │ ├── time_zone.rst
│ │ │ ├── tor_check.rst
│ │ │ └── unit_converter.rst
│ │ ├── quickstart.rst
│ │ ├── reST.rst
│ │ ├── result_types/
│ │ │ ├── answer.rst
│ │ │ ├── base_result.rst
│ │ │ ├── correction.rst
│ │ │ ├── index.rst
│ │ │ ├── infobox.rst
│ │ │ ├── main/
│ │ │ │ ├── code.rst
│ │ │ │ ├── file.rst
│ │ │ │ ├── keyvalue.rst
│ │ │ │ ├── mainresult.rst
│ │ │ │ └── paper.rst
│ │ │ ├── main_result.rst
│ │ │ └── suggestion.rst
│ │ ├── search_api.rst
│ │ ├── searxng_extra/
│ │ │ ├── index.rst
│ │ │ └── update.rst
│ │ ├── templates.rst
│ │ └── translation.rst
│ ├── index.rst
│ ├── own-instance.rst
│ ├── src/
│ │ ├── index.rst
│ │ ├── searx.babel_extract.rst
│ │ ├── searx.botdetection.rst
│ │ ├── searx.cache.rst
│ │ ├── searx.exceptions.rst
│ │ ├── searx.favicons.rst
│ │ ├── searx.infopage.rst
│ │ ├── searx.locales.rst
│ │ ├── searx.search.processors.rst
│ │ ├── searx.search.rst
│ │ ├── searx.settings.rst
│ │ ├── searx.sqlitedb.rst
│ │ ├── searx.utils.rst
│ │ ├── searx.valkeydb.rst
│ │ ├── searx.valkeylib.rst
│ │ └── searx.weather.rst
│ ├── user/
│ │ ├── .gitignore
│ │ ├── about.rst
│ │ ├── configured_engines.rst
│ │ ├── index.rst
│ │ └── search-syntax.rst
│ └── utils/
│ ├── index.rst
│ └── searxng.sh.rst
├── go.mod
├── go.sum
├── manage
├── mise.toml
├── package.json
├── pyrightconfig.json
├── requirements-dev.txt
├── requirements-server.txt
├── requirements.txt
├── searx/
│ ├── __init__.py
│ ├── answerers/
│ │ ├── __init__.py
│ │ ├── _core.py
│ │ ├── random.py
│ │ └── statistics.py
│ ├── autocomplete.py
│ ├── babel_extract.py
│ ├── botdetection/
│ │ ├── __init__.py
│ │ ├── _helpers.py
│ │ ├── config.py
│ │ ├── http_accept.py
│ │ ├── http_accept_encoding.py
│ │ ├── http_accept_language.py
│ │ ├── http_connection.py
│ │ ├── http_sec_fetch.py
│ │ ├── http_user_agent.py
│ │ ├── ip_limit.py
│ │ ├── ip_lists.py
│ │ ├── link_token.py
│ │ ├── trusted_proxies.py
│ │ └── valkeydb.py
│ ├── brand.py
│ ├── cache.py
│ ├── compat.py
│ ├── data/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── ahmia_blacklist.txt
│ │ ├── core.py
│ │ ├── currencies.json
│ │ ├── currencies.py
│ │ ├── engine_descriptions.json
│ │ ├── engine_traits.json
│ │ ├── external_bangs.json
│ │ ├── external_urls.json
│ │ ├── gsa_useragents.txt
│ │ ├── lid.176.ftz
│ │ ├── locales.json
│ │ ├── osm_keys_tags.json
│ │ ├── tracker_patterns.py
│ │ ├── useragents.json
│ │ └── wikidata_units.json
│ ├── enginelib/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ └── traits.py
│ ├── engines/
│ │ ├── 1337x.py
│ │ ├── 360search.py
│ │ ├── 360search_videos.py
│ │ ├── 9gag.py
│ │ ├── __builtins__.pyi
│ │ ├── __init__.py
│ │ ├── acfun.py
│ │ ├── adobe_stock.py
│ │ ├── ahmia.py
│ │ ├── alpinelinux.py
│ │ ├── annas_archive.py
│ │ ├── ansa.py
│ │ ├── aol.py
│ │ ├── apkmirror.py
│ │ ├── apple_app_store.py
│ │ ├── apple_maps.py
│ │ ├── archlinux.py
│ │ ├── artic.py
│ │ ├── artstation.py
│ │ ├── arxiv.py
│ │ ├── astrophysics_data_system.py
│ │ ├── azure.py
│ │ ├── baidu.py
│ │ ├── bandcamp.py
│ │ ├── base.py
│ │ ├── bilibili.py
│ │ ├── bing.py
│ │ ├── bing_images.py
│ │ ├── bing_news.py
│ │ ├── bing_videos.py
│ │ ├── bitchute.py
│ │ ├── boardreader.py
│ │ ├── bpb.py
│ │ ├── brave.py
│ │ ├── braveapi.py
│ │ ├── bt4g.py
│ │ ├── btdigg.py
│ │ ├── cachy_os.py
│ │ ├── cara.py
│ │ ├── ccc_media.py
│ │ ├── chefkoch.py
│ │ ├── chinaso.py
│ │ ├── cloudflareai.py
│ │ ├── command.py
│ │ ├── core.py
│ │ ├── crates.py
│ │ ├── crossref.py
│ │ ├── currency_convert.py
│ │ ├── dailymotion.py
│ │ ├── deepl.py
│ │ ├── deezer.py
│ │ ├── demo_offline.py
│ │ ├── demo_online.py
│ │ ├── destatis.py
│ │ ├── deviantart.py
│ │ ├── devicons.py
│ │ ├── dictzone.py
│ │ ├── digbt.py
│ │ ├── discourse.py
│ │ ├── docker_hub.py
│ │ ├── doku.py
│ │ ├── duckduckgo.py
│ │ ├── duckduckgo_definitions.py
│ │ ├── duckduckgo_extra.py
│ │ ├── duckduckgo_weather.py
│ │ ├── duden.py
│ │ ├── dummy-offline.py
│ │ ├── dummy.py
│ │ ├── ebay.py
│ │ ├── elasticsearch.py
│ │ ├── emojipedia.py
│ │ ├── fdroid.py
│ │ ├── findthatmeme.py
│ │ ├── flickr.py
│ │ ├── flickr_noapi.py
│ │ ├── freesound.py
│ │ ├── frinkiac.py
│ │ ├── fyyd.py
│ │ ├── geizhals.py
│ │ ├── genius.py
│ │ ├── gitea.py
│ │ ├── github.py
│ │ ├── github_code.py
│ │ ├── gitlab.py
│ │ ├── gmx.py
│ │ ├── goodreads.py
│ │ ├── google.py
│ │ ├── google_images.py
│ │ ├── google_news.py
│ │ ├── google_play.py
│ │ ├── google_scholar.py
│ │ ├── google_videos.py
│ │ ├── grokipedia.py
│ │ ├── hackernews.py
│ │ ├── hex.py
│ │ ├── huggingface.py
│ │ ├── il_post.py
│ │ ├── imdb.py
│ │ ├── imgur.py
│ │ ├── ina.py
│ │ ├── invidious.py
│ │ ├── ipernity.py
│ │ ├── iqiyi.py
│ │ ├── jisho.py
│ │ ├── json_engine.py
│ │ ├── karmasearch.py
│ │ ├── kickass.py
│ │ ├── lemmy.py
│ │ ├── lib_rs.py
│ │ ├── libretranslate.py
│ │ ├── lingva.py
│ │ ├── loc.py
│ │ ├── lucide.py
│ │ ├── marginalia.py
│ │ ├── mariadb_server.py
│ │ ├── mastodon.py
│ │ ├── material_icons.py
│ │ ├── mediathekviewweb.py
│ │ ├── mediawiki.py
│ │ ├── meilisearch.py
│ │ ├── metacpan.py
│ │ ├── microsoft_learn.py
│ │ ├── mixcloud.py
│ │ ├── mojeek.py
│ │ ├── mongodb.py
│ │ ├── moviepilot.py
│ │ ├── mozhi.py
│ │ ├── mrs.py
│ │ ├── mwmbl.py
│ │ ├── mysql_server.py
│ │ ├── naver.py
│ │ ├── niconico.py
│ │ ├── npm.py
│ │ ├── nvd.py
│ │ ├── nyaa.py
│ │ ├── odysee.py
│ │ ├── ollama.py
│ │ ├── open_meteo.py
│ │ ├── openalex.py
│ │ ├── openclipart.py
│ │ ├── openlibrary.py
│ │ ├── opensemantic.py
│ │ ├── openstreetmap.py
│ │ ├── openverse.py
│ │ ├── pdbe.py
│ │ ├── peertube.py
│ │ ├── pexels.py
│ │ ├── photon.py
│ │ ├── pinterest.py
│ │ ├── piped.py
│ │ ├── piratebay.py
│ │ ├── pixabay.py
│ │ ├── pixiv.py
│ │ ├── pkg_go_dev.py
│ │ ├── podcastindex.py
│ │ ├── postgresql.py
│ │ ├── presearch.py
│ │ ├── public_domain_image_archive.py
│ │ ├── pubmed.py
│ │ ├── pypi.py
│ │ ├── quark.py
│ │ ├── qwant.py
│ │ ├── radio_browser.py
│ │ ├── recoll.py
│ │ ├── reddit.py
│ │ ├── repology.py
│ │ ├── reuters.py
│ │ ├── rottentomatoes.py
│ │ ├── rumble.py
│ │ ├── scanr_structures.py
│ │ ├── searx_engine.py
│ │ ├── selfhst.py
│ │ ├── semantic_scholar.py
│ │ ├── senscritique.py
│ │ ├── sepiasearch.py
│ │ ├── seznam.py
│ │ ├── sogou.py
│ │ ├── sogou_images.py
│ │ ├── sogou_videos.py
│ │ ├── sogou_wechat.py
│ │ ├── solidtorrents.py
│ │ ├── solr.py
│ │ ├── soundcloud.py
│ │ ├── sourcehut.py
│ │ ├── spotify.py
│ │ ├── springer.py
│ │ ├── sqlite.py
│ │ ├── stackexchange.py
│ │ ├── startpage.py
│ │ ├── steam.py
│ │ ├── svgrepo.py
│ │ ├── tagesschau.py
│ │ ├── tineye.py
│ │ ├── tokyotoshokan.py
│ │ ├── tootfinder.py
│ │ ├── torznab.py
│ │ ├── translated.py
│ │ ├── tubearchivist.py
│ │ ├── unsplash.py
│ │ ├── uxwing.py
│ │ ├── valkey_server.py
│ │ ├── vimeo.py
│ │ ├── voidlinux.py
│ │ ├── wallhaven.py
│ │ ├── wikicommons.py
│ │ ├── wikidata.py
│ │ ├── wikipedia.py
│ │ ├── wolframalpha_api.py
│ │ ├── wolframalpha_noapi.py
│ │ ├── wordnik.py
│ │ ├── wttr.py
│ │ ├── www1x.py
│ │ ├── xpath.py
│ │ ├── yacy.py
│ │ ├── yahoo.py
│ │ ├── yahoo_news.py
│ │ ├── yandex.py
│ │ ├── yandex_music.py
│ │ ├── yep.py
│ │ ├── youtube_api.py
│ │ ├── youtube_noapi.py
│ │ └── zlibrary.py
│ ├── exceptions.py
│ ├── extended_types.py
│ ├── external_bang.py
│ ├── external_urls.py
│ ├── favicons/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── cache.py
│ │ ├── config.py
│ │ ├── favicons.toml
│ │ ├── proxy.py
│ │ └── resolvers.py
│ ├── flaskfix.py
│ ├── infopage/
│ │ ├── __init__.py
│ │ ├── de/
│ │ │ ├── about.md
│ │ │ ├── donate.md
│ │ │ └── search-syntax.md
│ │ ├── en/
│ │ │ ├── about.md
│ │ │ ├── donate.md
│ │ │ └── search-syntax.md
│ │ ├── fa_IR/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ ├── fr/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ ├── id/
│ │ │ ├── about.md
│ │ │ └── search-syntax.md
│ │ └── it/
│ │ ├── about.md
│ │ └── search-syntax.md
│ ├── limiter.py
│ ├── limiter.toml
│ ├── locales.py
│ ├── metrics/
│ │ ├── __init__.py
│ │ ├── error_recorder.py
│ │ └── models.py
│ ├── network/
│ │ ├── __init__.py
│ │ ├── client.py
│ │ ├── network.py
│ │ └── raise_for_httperror.py
│ ├── openmetrics.py
│ ├── plugins/
│ │ ├── __init__.py
│ │ ├── _core.py
│ │ ├── ahmia_filter.py
│ │ ├── calculator.py
│ │ ├── hash_plugin.py
│ │ ├── hostnames.py
│ │ ├── infinite_scroll.py
│ │ ├── oa_doi_rewrite.py
│ │ ├── self_info.py
│ │ ├── time_zone.py
│ │ ├── tor_check.py
│ │ ├── tracker_url_remover.py
│ │ └── unit_converter.py
│ ├── preferences.py
│ ├── query.py
│ ├── result_types/
│ │ ├── __init__.py
│ │ ├── _base.py
│ │ ├── answer.py
│ │ ├── code.py
│ │ ├── file.py
│ │ ├── keyvalue.py
│ │ └── paper.py
│ ├── results.py
│ ├── search/
│ │ ├── __init__.py
│ │ ├── models.py
│ │ └── processors/
│ │ ├── __init__.py
│ │ ├── abstract.py
│ │ ├── offline.py
│ │ ├── online.py
│ │ ├── online_currency.py
│ │ ├── online_dictionary.py
│ │ └── online_url_search.py
│ ├── searxng.msg
│ ├── settings.yml
│ ├── settings_defaults.py
│ ├── settings_loader.py
│ ├── sqlitedb.py
│ ├── static/
│ │ └── themes/
│ │ └── simple/
│ │ └── manifest.json
│ ├── sxng_locales.py
│ ├── templates/
│ │ └── simple/
│ │ ├── 404.html
│ │ ├── answer/
│ │ │ ├── legacy.html
│ │ │ ├── translations.html
│ │ │ └── weather.html
│ │ ├── base.html
│ │ ├── categories.html
│ │ ├── elements/
│ │ │ ├── answers.html
│ │ │ ├── apis.html
│ │ │ ├── corrections.html
│ │ │ ├── engines_msg.html
│ │ │ ├── infobox.html
│ │ │ ├── search_url.html
│ │ │ └── suggestions.html
│ │ ├── filters/
│ │ │ ├── languages.html
│ │ │ ├── safesearch.html
│ │ │ └── time_range.html
│ │ ├── icons.html
│ │ ├── index.html
│ │ ├── info.html
│ │ ├── macros.html
│ │ ├── manifest.json
│ │ ├── messages/
│ │ │ ├── no_cookies.html
│ │ │ └── no_results.html
│ │ ├── new_issue.html
│ │ ├── opensearch.xml
│ │ ├── opensearch_response_rss.xml
│ │ ├── page_with_header.html
│ │ ├── preferences/
│ │ │ ├── answerers.html
│ │ │ ├── autocomplete.html
│ │ │ ├── center_alignment.html
│ │ │ ├── cookies.html
│ │ │ ├── doi_resolver.html
│ │ │ ├── engines.html
│ │ │ ├── favicon.html
│ │ │ ├── footer.html
│ │ │ ├── hotkeys.html
│ │ │ ├── image_proxy.html
│ │ │ ├── language.html
│ │ │ ├── method.html
│ │ │ ├── query_in_title.html
│ │ │ ├── results_on_new_tab.html
│ │ │ ├── safesearch.html
│ │ │ ├── search_on_category_select.html
│ │ │ ├── theme.html
│ │ │ ├── tokens.html
│ │ │ ├── ui_locale.html
│ │ │ └── urlformatting.html
│ │ ├── preferences.html
│ │ ├── result_templates/
│ │ │ ├── code.html
│ │ │ ├── default.html
│ │ │ ├── file.html
│ │ │ ├── images.html
│ │ │ ├── keyvalue.html
│ │ │ ├── map.html
│ │ │ ├── packages.html
│ │ │ ├── paper.html
│ │ │ ├── products.html
│ │ │ ├── torrent.html
│ │ │ └── videos.html
│ │ ├── results.html
│ │ ├── rss.xsl
│ │ ├── search.html
│ │ ├── simple_search.html
│ │ └── stats.html
│ ├── translations/
│ │ ├── af/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ar/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bg/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bn/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── bo/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ca/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── cs/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── cy/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── da/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── de/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── dv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── el_GR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── en/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── eo/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── es/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── et/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── eu/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fa_IR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fi/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fil/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── fr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ga/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── gl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── he/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── hr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── hu/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ia/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── id/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── it/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ja/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ko/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── lt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── lv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── messages.pot
│ │ ├── ml/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ms/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── nb_NO/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── nl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── oc/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pa/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pap/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── pt_BR/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ro/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ru/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── si/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── sv/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── szl/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── ta/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── te/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── th/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── tr/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── tt/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── uk/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── vi/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ ├── zh_Hans_CN/
│ │ │ └── LC_MESSAGES/
│ │ │ ├── messages.mo
│ │ │ └── messages.po
│ │ └── zh_Hant_TW/
│ │ └── LC_MESSAGES/
│ │ ├── messages.mo
│ │ └── messages.po
│ ├── utils.py
│ ├── valkeydb.py
│ ├── valkeylib.py
│ ├── version.py
│ ├── weather.py
│ ├── webadapter.py
│ ├── webapp.py
│ ├── webutils.py
│ └── wikidata_units.py
├── searxng_extra/
│ ├── __init__.py
│ ├── docs_prebuild
│ └── update/
│ ├── __init__.py
│ ├── update_ahmia_blacklist.py
│ ├── update_currencies.py
│ ├── update_engine_descriptions.py
│ ├── update_engine_traits.py
│ ├── update_external_bangs.py
│ ├── update_firefox_version.py
│ ├── update_gsa_useragents.py
│ ├── update_locales.py
│ ├── update_osm_keys_tags.py
│ ├── update_pygments.py
│ └── update_wikidata_units.py
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── robot/
│ │ ├── __init__.py
│ │ ├── __main__.py
│ │ ├── settings_robot.yml
│ │ └── test_webapp.py
│ └── unit/
│ ├── __init__.py
│ ├── engines/
│ │ ├── __init__.py
│ │ ├── test_command.py
│ │ ├── test_json_engine.py
│ │ └── test_xpath.py
│ ├── network/
│ │ ├── __init__.py
│ │ └── test_network.py
│ ├── processors/
│ │ ├── __init__.py
│ │ └── test_online.py
│ ├── settings/
│ │ ├── empty_settings.yml
│ │ ├── limiter.toml
│ │ ├── syntaxerror_settings.yml
│ │ ├── test_github_code.yml
│ │ ├── test_result_container.yml
│ │ ├── test_settings.yml
│ │ ├── test_tineye.yml
│ │ ├── user_settings.yml
│ │ ├── user_settings_keep_only.yml
│ │ ├── user_settings_remove.yml
│ │ ├── user_settings_remove2.yml
│ │ └── user_settings_simple.yml
│ ├── test_answerers.py
│ ├── test_engine_github_code.py
│ ├── test_engine_tineye.py
│ ├── test_engines_init.py
│ ├── test_exceptions.py
│ ├── test_external_bangs.py
│ ├── test_js_variable_to_python.py
│ ├── test_locales.py
│ ├── test_plugin_hash.py
│ ├── test_plugin_self_info.py
│ ├── test_plugins.py
│ ├── test_preferences.py
│ ├── test_query.py
│ ├── test_results.py
│ ├── test_search.py
│ ├── test_settings_loader.py
│ ├── test_utils.py
│ ├── test_webadapter.py
│ ├── test_webapp.py
│ └── test_webutils.py
└── utils/
├── brand.sh
├── get_setting.py
├── lib.sh
├── lib_govm.sh
├── lib_nvm.sh
├── lib_redis.sh
├── lib_sxng_container.sh
├── lib_sxng_data.sh
├── lib_sxng_node.sh
├── lib_sxng_static.sh
├── lib_sxng_test.sh
├── lib_sxng_themes.sh
├── lib_sxng_vite.sh
├── lib_sxng_weblate.sh
├── lib_valkey.sh
├── makefile.include
├── searxng.sh
├── searxng_check.py
└── templates/
└── etc/
├── apt/
│ └── sources.list.d/
│ ├── debian-stable-backports.sources
│ └── ubuntu-stable-backports.sources
├── httpd/
│ └── sites-available/
│ ├── searxng.conf
│ └── searxng.conf:socket
├── nginx/
│ └── default.apps-available/
│ ├── searxng.conf
│ └── searxng.conf:socket
├── searxng/
│ └── settings.yml
└── uwsgi/
├── apps-archlinux/
│ ├── searxng.ini
│ └── searxng.ini:socket
└── apps-available/
├── searxng.ini
└── searxng.ini:socket
SYMBOL INDEX (2157 symbols across 369 files)
FILE: client/simple/src/js/Plugin.ts
method constructor (line 23) | protected constructor(id: string) {
method invoke (line 29) | private async invoke(): Promise<void> {
FILE: client/simple/src/js/loader.ts
type Options (line 6) | type Options =
FILE: client/simple/src/js/main/keyboard.ts
type KeyBindingLayout (line 6) | type KeyBindingLayout = "default" | "vim";
type KeyBinding (line 8) | type KeyBinding = {
type HighlightResultElement (line 15) | type HighlightResultElement = "down" | "up" | "visible" | "bottom" | "top";
FILE: client/simple/src/js/plugin/Calculator.ts
class Calculator (line 44) | class Calculator extends Plugin {
method constructor (line 45) | public constructor() {
method run (line 78) | protected async run(): Promise<string | undefined> {
method post (line 90) | protected async post(result: string): Promise<void> {
FILE: client/simple/src/js/plugin/InfiniteScroll.ts
class InfiniteScroll (line 11) | class InfiniteScroll extends Plugin {
method constructor (line 12) | public constructor() {
method run (line 16) | protected async run(): Promise<void> {
method post (line 107) | protected async post(): Promise<void> {
FILE: client/simple/src/js/plugin/MapView.ts
class MapView (line 16) | class MapView extends Plugin {
method constructor (line 19) | public constructor(map: HTMLElement) {
method run (line 25) | protected async run(): Promise<void> {
method post (line 90) | protected async post(): Promise<void> {
FILE: client/simple/src/js/toolkit.ts
type Settings (line 6) | type Settings = {
type HTTPOptions (line 25) | type HTTPOptions = {
type ReadyOptions (line 30) | type ReadyOptions = {
type EndpointsKeys (line 35) | type EndpointsKeys = keyof typeof Endpoints;
FILE: client/simple/src/js/util/assertElement.ts
type AssertElement (line 3) | type AssertElement = <T>(element?: T | null) => asserts element is T;
FILE: client/simple/src/js/util/getElement.ts
type Options (line 5) | type Options = {
function getElement (line 11) | function getElement<T>(id: string, options: Options = {}): T | null {
FILE: client/simple/theme_icons.ts
constant HERE (line 12) | const HERE = `${dirname(argv[1] || "")}/`;
FILE: client/simple/tools/img.ts
type Src2Dest (line 10) | type Src2Dest = {
FILE: client/simple/tools/jinja_svg_catalog.ts
type IconSet (line 11) | type IconSet = {
type IconSVG (line 21) | type IconSVG = {
type JinjaMacro (line 31) | type JinjaMacro = {
FILE: client/simple/vite.config.ts
constant ROOT (line 18) | const ROOT = "../../";
constant PATH (line 20) | const PATH = {
FILE: docs/conf.py
function setup (line 71) | def setup(app):
FILE: searx/__init__.py
function init_settings (line 32) | def init_settings():
function get_setting (line 74) | def get_setting(name: str, default: t.Any = _unset) -> t.Any:
function _is_color_terminal (line 97) | def _is_color_terminal():
function _logging_config_debug (line 103) | def _logging_config_debug():
FILE: searx/answerers/_core.py
class AnswererInfo (line 22) | class AnswererInfo:
class Answerer (line 43) | class Answerer(abc.ABC):
method answer (line 50) | def answer(self, query: str) -> list[BaseAnswer]:
method info (line 54) | def info(self) -> AnswererInfo:
class ModuleAnswerer (line 58) | class ModuleAnswerer(Answerer):
method __init__ (line 67) | def __init__(self, mod):
method answer (line 78) | def answer(self, query: str) -> list[BaseAnswer]:
method info (line 81) | def info(self) -> AnswererInfo:
class AnswerStorage (line 87) | class AnswerStorage(dict): # type: ignore
method __init__ (line 95) | def __init__(self):
method load_builtins (line 99) | def load_builtins(self):
method register_by_fqn (line 121) | def register_by_fqn(self, fqn: str):
method register (line 135) | def register(self, answerer: Answerer):
method ask (line 143) | def ask(self, query: str) -> list[BaseAnswer]:
method info (line 167) | def info(self) -> list[AnswererInfo]:
FILE: searx/answerers/random.py
function random_characters (line 17) | def random_characters():
function random_string (line 22) | def random_string():
function random_float (line 26) | def random_float():
function random_int (line 30) | def random_int():
function random_sha256 (line 35) | def random_sha256():
function random_uuid (line 41) | def random_uuid():
function random_color (line 45) | def random_color():
class SXNGAnswerer (line 50) | class SXNGAnswerer(Answerer):
method info (line 64) | def info(self):
method answer (line 73) | def answer(self, query: str) -> list[BaseAnswer]:
FILE: searx/answerers/statistics.py
class SXNGAnswerer (line 28) | class SXNGAnswerer(Answerer):
method info (line 33) | def info(self):
method answer (line 42) | def answer(self, query: str) -> list[BaseAnswer]:
FILE: searx/autocomplete.py
function update_kwargs (line 29) | def update_kwargs(**kwargs) -> None: # type: ignore
function get (line 35) | def get(*args, **kwargs) -> "SXNG_Response": # type: ignore
function post (line 40) | def post(*args, **kwargs) -> "SXNG_Response": # type: ignore
function baidu (line 45) | def baidu(query: str, _sxng_locale: str) -> list[str]:
function bing (line 59) | def bing(query: str, _sxng_locale: str) -> list[str]:
function brave (line 79) | def brave(query: str, _sxng_locale: str) -> list[str]:
function dbpedia (line 95) | def dbpedia(query: str, _sxng_locale: str) -> list[str]:
function duckduckgo (line 107) | def duckduckgo(query: str, sxng_locale: str) -> list[str]:
function google_complete (line 127) | def google_complete(query: str, sxng_locale: str) -> list[str]:
function mwmbl (line 156) | def mwmbl(query: str, _sxng_locale: str) -> list[str]:
function naver (line 168) | def naver(query: str, _sxng_locale: str) -> list[str]:
function qihu360search (line 182) | def qihu360search(query: str, _sxng_locale: str) -> list[str]:
function quark (line 196) | def quark(query: str, _sxng_locale: str) -> list[str]:
function seznam (line 209) | def seznam(query: str, _sxng_locale: str) -> list[str]:
function sogou (line 231) | def sogou(query: str, _sxng_locale: str) -> list[str]:
function startpage (line 247) | def startpage(query: str, sxng_locale: str) -> list[str]:
function swisscows (line 293) | def swisscows(query: str, _sxng_locale: str) -> list[str]:
function qwant (line 300) | def qwant(query: str, sxng_locale: str) -> list[str]:
function wikipedia (line 316) | def wikipedia(query: str, sxng_locale: str) -> list[str]:
function yandex (line 343) | def yandex(query: str, _sxng_locale: str) -> list[str]:
function search_autocomplete (line 375) | def search_autocomplete(backend_name: str, query: str, sxng_locale: str)...
FILE: searx/babel_extract.py
function extract (line 30) | def extract(
FILE: searx/botdetection/__init__.py
function init (line 22) | def init(cfg: config.Config, valkey_client: valkey.Valkey | None):
FILE: searx/botdetection/_helpers.py
function dump_request (line 26) | def dump_request(request: flask.Request):
function too_many_requests (line 45) | def too_many_requests(network: IPv4Network | IPv6Network, log_msg: str) ...
function get_network (line 56) | def get_network(real_ip: IPv4Address | IPv6Address, cfg: "config.Config"...
function log_error_only_once (line 83) | def log_error_only_once(err_msg: str):
FILE: searx/botdetection/config.py
function set_global_cfg (line 26) | def set_global_cfg(cfg: "Config"):
function get_global_cfg (line 31) | def get_global_cfg() -> "Config":
class FALSE (line 38) | class FALSE:
method __init__ (line 42) | def __init__(self, msg: str):
method __bool__ (line 45) | def __bool__(self):
method __str__ (line 48) | def __str__(self):
class SchemaIssue (line 58) | class SchemaIssue(ValueError):
method __init__ (line 61) | def __init__(self, level: typing.Literal['warn', 'invalid'], msg: str):
method __str__ (line 65) | def __str__(self):
class Config (line 69) | class Config:
method from_toml (line 75) | def from_toml(cls, schema_file: pathlib.Path, cfg_file: pathlib.Path, ...
method __init__ (line 98) | def __init__(self, cfg_schema: dict[str, typing.Any], deprecated: dict...
method __getitem__ (line 111) | def __getitem__(self, key: str) -> typing.Any:
method validate (line 114) | def validate(self, cfg: dict[str, typing.Any]):
method update (line 120) | def update(self, upd_cfg: dict[str, typing.Any]):
method default (line 125) | def default(self, name: str):
method get (line 129) | def get(self, name: str, default: typing.Any = UNSET, replace: bool = ...
method set (line 147) | def set(self, name: str, val: typing.Any):
method _get_parent_dict (line 156) | def _get_parent_dict(self, name: str) -> dict[str, typing.Any]:
method path (line 166) | def path(self, name: str, default: typing.Any = UNSET):
method pyobj (line 176) | def pyobj(self, name: str, default: typing.Any = UNSET):
function toml_load (line 190) | def toml_load(file_name: str | pathlib.Path):
function value (line 203) | def value(name: str, data_dict: dict[str, typing.Any]):
function validate (line 231) | def validate(
function _validate (line 272) | def _validate(
function dict_deepupdate (line 317) | def dict_deepupdate(base_dict: dict[str, typing.Any], upd_dict: dict[str...
FILE: searx/botdetection/http_accept.py
function filter_request (line 29) | def filter_request(
FILE: searx/botdetection/http_accept_encoding.py
function filter_request (line 30) | def filter_request(
FILE: searx/botdetection/http_accept_language.py
function filter_request (line 27) | def filter_request(
FILE: searx/botdetection/http_connection.py
function filter_request (line 27) | def filter_request(
FILE: searx/botdetection/http_sec_fetch.py
function is_browser_supported (line 39) | def is_browser_supported(user_agent: str) -> bool:
function filter_request (line 77) | def filter_request(
FILE: searx/botdetection/http_user_agent.py
function regexp_user_agent (line 49) | def regexp_user_agent():
function filter_request (line 56) | def filter_request(
FILE: searx/botdetection/ip_limit.py
function filter_request (line 92) | def filter_request(
FILE: searx/botdetection/ip_lists.py
function pass_ip (line 49) | def pass_ip(real_ip: IPv4Address | IPv6Address, cfg: config.Config) -> T...
function block_ip (line 62) | def block_ip(real_ip: IPv4Address | IPv6Address, cfg: config.Config) -> ...
function ip_is_subnet_of_member_in_list (line 73) | def ip_is_subnet_of_member_in_list(
FILE: searx/botdetection/link_token.py
function is_suspicious (line 73) | def is_suspicious(network: IPv4Network | IPv6Network, request: flask.Req...
function ping (line 93) | def ping(request: flask.Request, token: str):
function get_ping_key (line 115) | def get_ping_key(network: IPv4Network | IPv6Network, request: flask.Requ...
function token_is_valid (line 128) | def token_is_valid(token) -> bool:
function get_token (line 134) | def get_token() -> str:
FILE: searx/botdetection/trusted_proxies.py
class ProxyFix (line 23) | class ProxyFix:
method __init__ (line 58) | def __init__(self, wsgi_app: "WSGIApplication") -> None:
method trusted_proxies (line 61) | def trusted_proxies(self) -> list[IPv4Network | IPv6Network]:
method trusted_remote_addr (line 66) | def trusted_remote_addr(
method __call__ (line 88) | def __call__(self, environ: "WSGIEnvironment", start_response: "StartR...
FILE: searx/botdetection/valkeydb.py
function set_valkey_client (line 13) | def set_valkey_client(valkey_client: valkey.Valkey):
function get_valkey_client (line 18) | def get_valkey_client() -> valkey.Valkey:
FILE: searx/brand.py
class BrandCustom (line 14) | class BrandCustom(msgspec.Struct, kw_only=True, forbid_unknown_fields=Tr...
class ThemeColors (line 21) | class ThemeColors(msgspec.Struct, kw_only=True, forbid_unknown_fields=Tr...
class SettingsBrand (line 32) | class SettingsBrand(msgspec.Struct, kw_only=True, forbid_unknown_fields=...
FILE: searx/cache.py
class ExpireCacheCfg (line 35) | class ExpireCacheCfg(msgspec.Struct): # pylint: disable=too-few-public-...
method __post_init__ (line 76) | def __post_init__(self):
class ExpireCacheStats (line 83) | class ExpireCacheStats:
method report (line 101) | def report(self):
class ExpireCache (line 130) | class ExpireCache(abc.ABC):
method set (line 139) | def set(self, key: str, value: typing.Any, expire: int | None, ctx: st...
method get (line 159) | def get(self, key: str, default: typing.Any = None, ctx: str | None = ...
method maintenance (line 163) | def maintenance(self, force: bool = False, truncate: bool = False) -> ...
method state (line 176) | def state(self) -> ExpireCacheStats:
method build_cache (line 181) | def build_cache(cfg: ExpireCacheCfg) -> "ExpireCacheSQLite":
method normalize_name (line 193) | def normalize_name(name: str) -> str:
method serialize (line 200) | def serialize(self, value: typing.Any) -> bytes:
method deserialize (line 204) | def deserialize(self, value: bytes) -> typing.Any:
method secret_hash (line 208) | def secret_hash(self, name: str | bytes) -> str:
class ExpireCacheSQLite (line 220) | class ExpireCacheSQLite(sqlitedb.SQLiteAppl, ExpireCache):
method __init__ (line 240) | def __init__(self, cfg: ExpireCacheCfg):
method init (line 249) | def init(self, conn: sqlite3.Connection) -> bool:
method maintenance (line 264) | def maintenance(self, force: bool = False, truncate: bool = False) -> ...
method create_table (line 294) | def create_table(self, table: str) -> bool:
method table_names (line 322) | def table_names(self) -> list[str]:
method truncate_tables (line 328) | def truncate_tables(self, table_names: list[str]):
method next_maintenance_time (line 337) | def next_maintenance_time(self) -> int:
method set (line 344) | def set(self, key: str, value: typing.Any, expire: int | None, ctx: st...
method setmany (line 360) | def setmany(
method _setmany (line 385) | def _setmany(
method get (line 444) | def get(self, key: str, default: typing.Any = None, ctx: str | None = ...
method pairs (line 467) | def pairs(self, ctx: str) -> Iterator[tuple[str, typing.Any]]:
method state (line 481) | def state(self) -> ExpireCacheStats:
FILE: searx/compat.py
function limiter_fix_cfg (line 18) | def limiter_fix_cfg(cfg, cfg_file):
FILE: searx/data/__init__.py
class UserAgentType (line 19) | class UserAgentType(t.TypedDict):
class WikiDataUnitType (line 27) | class WikiDataUnitType(t.TypedDict):
class LocalesType (line 35) | class LocalesType(t.TypedDict):
function __getattr__ (line 81) | def __getattr__(name: str) -> t.Any:
function ahmia_blacklist_loader (line 98) | def ahmia_blacklist_loader() -> list[str]:
function gsa_useragents_loader (line 111) | def gsa_useragents_loader() -> list[str]:
FILE: searx/data/__main__.py
function state (line 12) | def state():
FILE: searx/data/core.py
function get_cache (line 17) | def get_cache():
FILE: searx/data/currencies.py
class CurrenciesDB (line 17) | class CurrenciesDB:
method __init__ (line 25) | def __init__(self):
method init (line 28) | def init(self):
method load (line 37) | def load(self):
method name_to_iso4217 (line 47) | def name_to_iso4217(self, name: str) -> str | None:
method iso4217_to_name (line 56) | def iso4217_to_name(self, iso4217: str, language: str) -> str | None:
method is_iso4217 (line 62) | def is_iso4217(self, iso4217: str) -> bool:
FILE: searx/data/tracker_patterns.py
class TrackerPatternsDB (line 26) | class TrackerPatternsDB:
class Fields (line 38) | class Fields:
method __init__ (line 44) | def __init__(self):
method init (line 47) | def init(self):
method load (line 56) | def load(self):
method add (line 70) | def add(self, rule: RuleType):
method rules (line 78) | def rules(self) -> Iterator[RuleType]:
method iter_clear_list (line 83) | def iter_clear_list(self) -> Iterator[RuleType]:
method clean_url (line 111) | def clean_url(self, url: str) -> bool | str:
FILE: searx/enginelib/__init__.py
function state (line 60) | def state():
function maintenance (line 75) | def maintenance(force: bool = True, truncate: bool = False):
class EngineCache (line 80) | class EngineCache:
method __init__ (line 160) | def __init__(self, engine_name: str, expire: int | None = None):
method set (line 165) | def set(self, key: str, value: t.Any, expire: int | None = None) -> bool:
method get (line 173) | def get(self, key: str, default: t.Any = None) -> t.Any:
method secret_hash (line 176) | def secret_hash(self, name: str | bytes) -> str:
class Engine (line 180) | class Engine(abc.ABC): # pylint: disable=too-few-public-methods
method setup (line 313) | def setup(self, engine_settings: dict[str, t.Any]) -> bool: # pylint:...
method init (line 329) | def init(self, engine_settings: dict[str, t.Any]) -> bool | None: # p...
method search (line 348) | def search(self, query: str, params: "OfflineParamTypes") -> "EngineRe...
method request (line 352) | def request(self, query: str, params: "OnlineParamTypes") -> None:
method response (line 357) | def response(self, resp: "SXNG_Response") -> "EngineResults":
FILE: searx/enginelib/traits.py
class EngineTraitsEncoder (line 25) | class EngineTraitsEncoder(json.JSONEncoder):
method default (line 29) | def default(self, o: t.Any) -> t.Any:
class EngineTraits (line 37) | class EngineTraits:
method get_language (line 87) | def get_language(self, searxng_locale: str, default: str | None = None...
method get_region (line 103) | def get_region(self, searxng_locale: str, default: str | None = None) ...
method is_locale_supported (line 119) | def is_locale_supported(self, searxng_locale: str) -> bool:
method copy (line 132) | def copy(self):
method fetch_traits (line 137) | def fetch_traits(cls, engine: "Engine | types.ModuleType") -> "EngineT...
method set_traits (line 151) | def set_traits(self, engine: "Engine | types.ModuleType") -> None:
method _set_traits_v1 (line 162) | def _set_traits_v1(self, engine: "Engine | types.ModuleType") -> None:
class EngineTraitsMap (line 193) | class EngineTraitsMap(dict[str, EngineTraits]):
method save_data (line 199) | def save_data(self):
method from_data (line 205) | def from_data(cls) -> "EngineTraitsMap":
method fetch_traits (line 213) | def fetch_traits(cls, log: t.Callable[[str], None]) -> "EngineTraitsMap":
method set_traits (line 245) | def set_traits(self, engine: "Engine | types.ModuleType"):
FILE: searx/engines/1337x.py
function request (line 25) | def request(query, params):
function response (line 31) | def response(resp):
FILE: searx/engines/360search.py
function setup (line 44) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function get_cookie (line 56) | def get_cookie(url: str) -> str:
function request (line 68) | def request(query, params):
function response (line 86) | def response(resp):
FILE: searx/engines/360search_videos.py
function request (line 25) | def request(query, params):
function response (line 32) | def response(resp):
FILE: searx/engines/9gag.py
function request (line 25) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/__init__.py
function check_engine_module (line 69) | def check_engine_module(module: types.ModuleType):
function load_engine (line 81) | def load_engine(engine_data: dict[str, t.Any]) -> "Engine | types.Module...
function set_loggers (line 159) | def set_loggers(engine: "Engine|types.ModuleType", engine_name: str):
function update_engine_attributes (line 178) | def update_engine_attributes(engine: "Engine | types.ModuleType", engine...
function update_attributes_for_tor (line 196) | def update_attributes_for_tor(engine: "Engine | types.ModuleType"):
function is_missing_required_attributes (line 202) | def is_missing_required_attributes(engine: "Engine | types.ModuleType"):
function using_tor_proxy (line 215) | def using_tor_proxy(engine: "Engine | types.ModuleType"):
function is_engine_active (line 220) | def is_engine_active(engine: "Engine | types.ModuleType"):
function call_engine_setup (line 232) | def call_engine_setup(engine: "Engine | types.ModuleType", engine_data: ...
function register_engine (line 251) | def register_engine(engine: "Engine | types.ModuleType"):
function load_engines (line 266) | def load_engines(engine_list: list[dict[str, t.Any]]):
FILE: searx/engines/acfun.py
function request (line 30) | def request(query, params):
function response (line 36) | def response(resp):
function extract_video_data (line 67) | def extract_video_data(video_block):
FILE: searx/engines/adobe_stock.py
function init (line 88) | def init(_):
function request (line 112) | def request(query, params):
function parse_image_item (line 134) | def parse_image_item(item):
function parse_video_item (line 148) | def parse_video_item(item):
function parse_audio_item (line 184) | def parse_audio_item(item):
function response (line 202) | def response(resp):
FILE: searx/engines/ahmia.py
function setup (line 49) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function _get_tokens (line 55) | def _get_tokens(dom: ElementType | None = None) -> str:
function request (line 71) | def request(query, params):
function response (line 86) | def response(resp):
FILE: searx/engines/alpinelinux.py
function request (line 40) | def request(query, params):
function response (line 57) | def response(resp):
FILE: searx/engines/annas_archive.py
function setup (line 99) | def setup(_engine_settings: dict[str, t.Any]) -> bool:
function _get_base_url_choice (line 119) | def _get_base_url_choice() -> str:
function request (line 126) | def request(query: str, params: "OnlineParams") -> None:
function response (line 143) | def response(resp: "SXNG_Response") -> EngineResults:
function _get_result (line 161) | def _get_result(item: ElementBase, base_url_choice: str) -> dict[str, t....
function fetch_traits (line 239) | def fetch_traits(engine_traits: EngineTraits) -> None:
FILE: searx/engines/ansa.py
function request (line 49) | def request(query, params):
function response (line 63) | def response(resp) -> EngineResults:
FILE: searx/engines/aol.py
function init (line 64) | def init(_):
function request (line 69) | def request(query: str, params: "OnlineParams") -> None:
function _deobfuscate_url (line 94) | def _deobfuscate_url(obfuscated_url: str) -> str | None:
function _general_results (line 106) | def _general_results(doc: html.HtmlElement) -> EngineResults:
function _video_results (line 129) | def _video_results(doc: html.HtmlElement) -> EngineResults:
function _image_results (line 164) | def _image_results(doc: html.HtmlElement) -> EngineResults:
function response (line 192) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/apkmirror.py
function request (line 34) | def request(query, params):
function response (line 43) | def response(resp):
FILE: searx/engines/apple_app_store.py
function request (line 26) | def request(query, params):
function response (line 37) | def response(resp):
FILE: searx/engines/apple_maps.py
function obtain_token (line 28) | def obtain_token():
function request (line 46) | def request(query, params):
function response (line 57) | def response(resp):
FILE: searx/engines/archlinux.py
function request (line 40) | def request(query, params):
function response (line 69) | def response(resp):
function fetch_traits (line 93) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/artic.py
function request (line 30) | def request(query, params):
function response (line 46) | def response(resp):
FILE: searx/engines/artstation.py
function setup (line 38) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function fetch_csrf_tokens (line 44) | def fetch_csrf_tokens():
function request (line 62) | def request(query, params):
function response (line 84) | def response(resp) -> EngineResults:
FILE: searx/engines/arxiv.py
function request (line 68) | def request(query: str, params: "OnlineParams") -> None:
function response (line 78) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/astrophysics_data_system.py
function setup (line 99) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function request (line 110) | def request(query: str, params: "OnlineParams") -> None:
function response (line 125) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/azure.py
function setup (line 65) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function authenticate (line 86) | def authenticate(t_id: str, c_id: str, c_secret: str) -> str:
function get_auth_token (line 104) | def get_auth_token(t_id: str, c_id: str, c_secret: str) -> str:
function request (line 114) | def request(query: str, params: "OnlineParams") -> None:
function response (line 157) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/baidu.py
function init (line 39) | def init(_):
function request (line 44) | def request(query, params):
function response (line 96) | def response(resp):
function parse_general (line 111) | def parse_general(data):
function parse_images (line 142) | def parse_images(data):
function parse_it (line 173) | def parse_it(data):
FILE: searx/engines/bandcamp.py
function request (line 39) | def request(query, params):
function response (line 46) | def response(resp):
FILE: searx/engines/base.py
function request (line 54) | def request(query, params):
function response (line 74) | def response(resp):
FILE: searx/engines/bilibili.py
function request (line 43) | def request(query, params):
function response (line 60) | def response(resp):
FILE: searx/engines/bing.py
function get_locale_params (line 55) | def get_locale_params(engine_region: str | None) -> dict[str, str] | None:
function override_accept_language (line 75) | def override_accept_language(params: "OnlineParams", engine_region: str ...
function request (line 97) | def request(query: str, params: "OnlineParams") -> "OnlineParams":
function response (line 122) | def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
function fetch_traits (line 171) | def fetch_traits(engine_traits: EngineTraits) -> None:
FILE: searx/engines/bing_images.py
function request (line 41) | def request(query, params):
function response (line 72) | def response(resp):
FILE: searx/engines/bing_news.py
function request (line 51) | def request(query, params):
function response (line 82) | def response(resp):
function fetch_traits (line 132) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/bing_videos.py
function request (line 36) | def request(query, params):
function response (line 68) | def response(resp):
FILE: searx/engines/bitchute.py
function request (line 23) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/boardreader.py
function init (line 47) | def init(engine_settings: dict[str, t.Any]) -> bool:
function _get_session_id (line 53) | def _get_session_id() -> str:
function request (line 70) | def request(query: str, params: "OnlineParams"):
function _remove_keyword_marker (line 89) | def _remove_keyword_marker(text: str) -> str:
function response (line 96) | def response(resp: "SXNG_Response") -> EngineResults:
function fetch_traits (line 114) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/bpb.py
function request (line 26) | def request(query, params):
function response (line 37) | def response(resp):
FILE: searx/engines/brave.py
function request (line 197) | def request(query: str, params: dict[str, t.Any]) -> None:
function _extract_published_date (line 234) | def _extract_published_date(published_date_raw: str | None):
function extract_json_data (line 243) | def extract_json_data(text: str) -> dict[str, t.Any]:
function response (line 264) | def response(resp: SXNG_Response) -> EngineResults:
function _parse_search (line 289) | def _parse_search(resp: SXNG_Response) -> EngineResults:
function _parse_news (line 352) | def _parse_news(resp: SXNG_Response) -> EngineResults:
function _parse_images (line 377) | def _parse_images(json_resp: dict[str, t.Any]) -> EngineResults:
function _parse_videos (line 394) | def _parse_videos(json_resp: dict[str, t.Any]) -> EngineResults:
function fetch_traits (line 418) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/braveapi.py
function init (line 66) | def init(_):
function request (line 72) | def request(query: str, params: "OnlineParams") -> None:
function _extract_published_date (line 92) | def _extract_published_date(published_date_raw: str):
function response (line 110) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/bt4g.py
function request (line 75) | def request(query, params):
function response (line 90) | def response(resp):
FILE: searx/engines/btdigg.py
function request (line 31) | def request(query, params):
function response (line 38) | def response(resp):
FILE: searx/engines/cachy_os.py
function request (line 23) | def request(query, params):
function response (line 35) | def response(resp) -> EngineResults:
FILE: searx/engines/cara.py
function request (line 43) | def request(query: str, params: "OnlineParams") -> None:
function response (line 53) | def response(resp: "SXNG_Response"):
FILE: searx/engines/ccc_media.py
function request (line 22) | def request(query, params):
function response (line 29) | def response(resp):
FILE: searx/engines/chefkoch.py
function request (line 27) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/chinaso.py
function init (line 111) | def init(_):
function request (line 118) | def request(query, params):
function response (line 153) | def response(resp):
function parse_news (line 164) | def parse_news(data):
function parse_images (line 188) | def parse_images(data):
function parse_videos (line 207) | def parse_videos(data):
FILE: searx/engines/cloudflareai.py
function request (line 29) | def request(query, params):
function response (line 53) | def response(resp):
FILE: searx/engines/command.py
function init (line 103) | def init(engine_settings):
function search (line 129) | def search(query, params) -> EngineResults:
function _get_command_to_run (line 142) | def _get_command_to_run(query):
function _get_results_from_process (line 156) | def _get_results_from_process(res: EngineResults, cmd, pageno):
function __get_results_limits (line 190) | def __get_results_limits(pageno):
function __check_query_params (line 196) | def __check_query_params(params):
function check_parsing_options (line 211) | def check_parsing_options(engine_settings):
function __parse_single_result (line 224) | def __parse_single_result(raw_result):
FILE: searx/engines/core.py
function setup (line 63) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function request (line 75) | def request(query: str, params: "OnlineParams") -> None:
function response (line 89) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/crates.py
function request (line 35) | def request(query: str, params):
function response (line 42) | def response(resp):
FILE: searx/engines/crossref.py
function request (line 39) | def request(query: str, params: "OnlineParams") -> None:
function response (line 47) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/currency_convert.py
function request (line 32) | def request(query: str, params: "OnlineCurrenciesParams") -> None: # py...
function response (line 36) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/dailymotion.py
function request (line 98) | def request(query, params):
function response (line 144) | def response(resp):
function fetch_traits (line 196) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/deepl.py
function request (line 22) | def request(_query, params):
function response (line 42) | def response(resp) -> EngineResults:
FILE: searx/engines/deezer.py
function request (line 30) | def request(query, params):
function response (line 39) | def response(resp):
FILE: searx/engines/demo_offline.py
function setup (line 54) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function init (line 77) | def init(engine_settings: dict[str, t.Any]) -> bool: # pylint: disable=...
function search (line 85) | def search(query: str, params: "RequestParams") -> EngineResults:
FILE: searx/engines/demo_online.py
function setup (line 60) | def setup(engine_settings: "OnlineParams") -> bool:
function init (line 69) | def init(engine_settings: dict[str, t.Any]) -> bool: # pylint: disable=...
function request (line 76) | def request(query: str, params: "OnlineParams") -> None:
function response (line 90) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/destatis.py
function request (line 33) | def request(query, params):
function response (line 42) | def response(resp):
FILE: searx/engines/deviantart.py
function request (line 36) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/devicons.py
function request (line 25) | def request(query: str, params: "OnlineParams"):
function response (line 31) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/dictzone.py
function request (line 29) | def request(query, params): # pylint: disable=unused-argument
function _clean_up_node (line 39) | def _clean_up_node(node):
function response (line 45) | def response(resp) -> EngineResults:
FILE: searx/engines/digbt.py
function request (line 29) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/discourse.py
function request (line 101) | def request(query, params):
function response (line 132) | def response(resp):
FILE: searx/engines/docker_hub.py
function request (line 24) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/doku.py
function request (line 40) | def request(query, params):
function response (line 48) | def response(resp):
FILE: searx/engines/duckduckgo.py
function get_cache (line 222) | def get_cache() -> EngineCache:
function set_vqd (line 229) | def set_vqd(query: str | int, value: str, params: "OnlineParams") -> None:
function get_vqd (line 235) | def get_vqd(
function get_ddg_lang (line 253) | def get_ddg_lang(
function quote_ddg_bangs (line 345) | def quote_ddg_bangs(query: str) -> str:
function request (line 361) | def request(query: str, params: "OnlineParams") -> None:
function is_ddg_captcha (line 458) | def is_ddg_captcha(dom: ElementType):
function response (line 465) | def response(resp: "SXNG_Response") -> EngineResults:
function fetch_traits (line 521) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/duckduckgo_definitions.py
function is_broken_text (line 50) | def is_broken_text(text: str) -> bool:
function result_to_text (line 60) | def result_to_text(text: str, htmlResult: str) -> str | None:
function request (line 74) | def request(query: str, params: "OnlineParams") -> None:
function response (line 78) | def response(resp: "SXNG_Response") -> EngineResults:
function unit_to_str (line 247) | def unit_to_str(unit: str) -> str:
function area_to_str (line 258) | def area_to_str(area: dict[str, str]) -> str:
FILE: searx/engines/duckduckgo_extra.py
function init (line 47) | def init(engine_settings: dict[str, t.Any]):
function fetch_vqd (line 53) | def fetch_vqd(
function request (line 83) | def request(query: str, params: "OnlineParams") -> None:
function _image_result (line 147) | def _image_result(result):
function _video_result (line 160) | def _video_result(result):
function _news_result (line 174) | def _news_result(result):
function response (line 184) | def response(resp):
FILE: searx/engines/duckduckgo_weather.py
function _weather_data (line 73) | def _weather_data(location: weather.GeoLocation, data: dict[str, t.Any]):
function request (line 88) | def request(query: str, params: dict[str, t.Any]):
function response (line 103) | def response(resp: SXNG_Response):
FILE: searx/engines/duden.py
function request (line 29) | def request(query, params):
function response (line 44) | def response(resp):
FILE: searx/engines/dummy-offline.py
function search (line 16) | def search(query, request_params): # pylint: disable=unused-argument
FILE: searx/engines/dummy.py
function request (line 16) | def request(query, params): # pylint: disable=unused-argument
function response (line 21) | def response(resp): # pylint: disable=unused-argument
FILE: searx/engines/ebay.py
function request (line 39) | def request(query, params):
function response (line 44) | def response(resp):
FILE: searx/engines/elasticsearch.py
function init (line 71) | def init(engine_settings):
function request (line 79) | def request(query, params):
function _match_query (line 101) | def _match_query(query):
function _simple_query_string_query (line 116) | def _simple_query_string_query(query):
function _term_query (line 126) | def _term_query(query):
function _terms_query (line 141) | def _terms_query(query):
function _custom_query (line 156) | def _custom_query(query):
function response (line 167) | def response(resp: SXNG_Response) -> EngineResults:
FILE: searx/engines/emojipedia.py
function request (line 34) | def request(query, params):
function response (line 41) | def response(resp):
FILE: searx/engines/fdroid.py
function request (line 30) | def request(query, params):
function response (line 37) | def response(resp):
FILE: searx/engines/findthatmeme.py
function request (line 21) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/flickr.py
function build_flickr_url (line 39) | def build_flickr_url(user_id, photo_id):
function request (line 43) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/flickr_noapi.py
function build_flickr_url (line 40) | def build_flickr_url(user_id, photo_id):
function _get_time_range_url (line 44) | def _get_time_range_url(time_range):
function request (line 50) | def request(query, params):
function response (line 57) | def response(resp): # pylint: disable=too-many-branches
FILE: searx/engines/freesound.py
function request (line 34) | def request(query, params):
function response (line 44) | def response(resp):
FILE: searx/engines/frinkiac.py
function request (line 28) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/fyyd.py
function request (line 21) | def request(query, params):
function response (line 31) | def response(resp):
FILE: searx/engines/geizhals.py
function request (line 47) | def request(query, params):
function response (line 67) | def response(resp):
FILE: searx/engines/genius.py
function request (line 28) | def request(query, params):
function parse_lyric (line 38) | def parse_lyric(hit):
function parse_artist (line 64) | def parse_artist(hit):
function parse_album (line 74) | def parse_album(hit):
function response (line 93) | def response(resp):
FILE: searx/engines/gitea.py
function init (line 80) | def init(_):
function request (line 85) | def request(query, params):
function response (line 92) | def response(resp):
FILE: searx/engines/github.py
function request (line 25) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/github_code.py
function request (line 144) | def request(query: str, params: dict[str, t.Any]) -> None:
function extract_code (line 162) | def extract_code(code_matches: list[dict[str, t.Any]]) -> tuple[list[str...
function response (line 214) | def response(resp: SXNG_Response) -> EngineResults:
FILE: searx/engines/gitlab.py
function request (line 67) | def request(query, params):
function response (line 74) | def response(resp):
FILE: searx/engines/gmx.py
function _get_page_hash (line 40) | def _get_page_hash(query: str, page: int, headers: dict[str, str]) -> str:
function request (line 48) | def request(query: str, params: 'OnlineParams'):
function response (line 78) | def response(resp: 'SXNG_Response') -> EngineResults:
FILE: searx/engines/goodreads.py
function request (line 30) | def request(query, params):
function response (line 40) | def response(resp):
FILE: searx/engines/google.py
function ui_async (line 79) | def ui_async(start: int) -> str:
function get_google_info (line 101) | def get_google_info(params: "OnlineParams", eng_traits: EngineTraits) ->...
function detect_google_sorry (line 281) | def detect_google_sorry(resp: "SXNG_Response"):
function request (line 304) | def request(query: str, params: "OnlineParams") -> None:
function parse_url_images (line 353) | def parse_url_images(text: str):
function response (line 362) | def response(resp: "SXNG_Response"):
function fetch_traits (line 460) | def fetch_traits(engine_traits: EngineTraits, add_domains: bool = True):
FILE: searx/engines/google_images.py
function request (line 51) | def request(query, params):
function response (line 82) | def response(resp):
FILE: searx/engines/google_news.py
function request (line 78) | def request(query: str, params: "OnlineParams") -> None:
function response (line 131) | def response(resp: "SXNG_Response") -> EngineResults:
function fetch_traits (line 301) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/google_play.py
function request (line 27) | def request(query, params):
function response (line 41) | def response(resp):
function response_movies (line 51) | def response_movies(resp):
function response_apps (line 78) | def response_apps(resp):
FILE: searx/engines/google_scholar.py
function request (line 76) | def request(query: str, params: "OnlineParams") -> None:
function response (line 97) | def response(resp: "SXNG_Response") -> EngineResults: # pylint: disable...
function time_range_args (line 173) | def time_range_args(params: "OnlineParams") -> dict[str, int]:
function detect_google_captcha (line 199) | def detect_google_captcha(dom: ElementType):
function parse_gs_a (line 207) | def parse_gs_a(text: str | None) -> tuple[list[str], str, str, datetime ...
FILE: searx/engines/google_videos.py
function parse_data_images (line 59) | def parse_data_images(text: str):
function request (line 71) | def request(query, params):
function response (line 104) | def response(resp):
FILE: searx/engines/grokipedia.py
function request (line 23) | def request(query, params):
function response (line 38) | def response(resp) -> EngineResults:
FILE: searx/engines/hackernews.py
function request (line 31) | def request(query, params):
function response (line 71) | def response(resp):
FILE: searx/engines/hex.py
function request (line 52) | def request(query: str, params):
function response (line 58) | def response(resp):
FILE: searx/engines/huggingface.py
function init (line 65) | def init(_):
function request (line 70) | def request(query, params):
function response (line 81) | def response(resp) -> EngineResults:
FILE: searx/engines/il_post.py
function request (line 41) | def request(query, params):
function response (line 57) | def response(resp) -> EngineResults:
FILE: searx/engines/imdb.py
function request (line 39) | def request(query, params):
function response (line 47) | def response(resp):
FILE: searx/engines/imgur.py
function request (line 29) | def request(query, params):
function response (line 40) | def response(resp):
FILE: searx/engines/ina.py
function request (line 41) | def request(query, params):
function response (line 47) | def response(resp):
FILE: searx/engines/invidious.py
function init (line 37) | def init(_):
function request (line 42) | def request(query, params):
function response (line 69) | def response(resp):
FILE: searx/engines/ipernity.py
function request (line 28) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/iqiyi.py
function request (line 29) | def request(query, params):
function _result (line 39) | def _result(video: dict[str, typing.Any], album_info: dict[str, typing.A...
function response (line 61) | def response(resp):
FILE: searx/engines/jisho.py
function request (line 27) | def request(query, params):
function response (line 34) | def response(resp):
function get_definitions (line 75) | def get_definitions(page):
function get_infobox (line 103) | def get_infobox(alt_forms, result_url, definitions):
FILE: searx/engines/json_engine.py
function iterate (line 256) | def iterate(iterable):
function is_iterable (line 266) | def is_iterable(obj):
function parse (line 272) | def parse(query): # pylint: disable=redefined-outer-name
function do_query (line 281) | def do_query(data, q): # pylint: disable=invalid-name
function query (line 305) | def query(data, query_string):
function request (line 311) | def request(query, params): # pylint: disable=redefined-outer-name
function identity (line 351) | def identity(arg):
function extract_response_info (line 355) | def extract_response_info(result):
function response (line 386) | def response(resp):
FILE: searx/engines/karmasearch.py
function init (line 48) | def init(_):
function request (line 53) | def request(query: str, params: "OnlineParams") -> None:
function _parse_date (line 73) | def _parse_date(date_string: str) -> datetime | None:
function _parse_general (line 80) | def _parse_general(result: dict[str, str]):
function _parse_news (line 89) | def _parse_news(result: dict[str, str]) -> LegacyResult:
function _parse_videos (line 101) | def _parse_videos(result: dict[str, t.Any]) -> LegacyResult:
function _parse_images (line 115) | def _parse_images(result: dict[str, t.Any]) -> LegacyResult:
function response (line 128) | def response(resp: "SXNG_Response") -> EngineResults:
function fetch_traits (line 162) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/kickass.py
function request (line 33) | def request(query, params):
function response (line 40) | def response(resp):
FILE: searx/engines/lemmy.py
function request (line 68) | def request(query, params):
function _get_communities (line 79) | def _get_communities(json):
function _get_users (line 102) | def _get_users(json):
function _get_posts (line 117) | def _get_posts(json):
function _get_comments (line 152) | def _get_comments(json):
function response (line 181) | def response(resp):
FILE: searx/engines/lib_rs.py
function request (line 29) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/libretranslate.py
function request (line 24) | def request(_query, params):
function response (line 48) | def response(resp) -> EngineResults:
FILE: searx/engines/lingva.py
function request (line 32) | def request(_query: str, params: "OnlineDictParams") -> None:
function response (line 40) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/loc.py
function request (line 34) | def request(query, params):
function response (line 46) | def response(resp):
FILE: searx/engines/lucide.py
function request (line 30) | def request(query: str, params: "OnlineParams"):
function response (line 36) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/marginalia.py
class ApiSearchResult (line 59) | class ApiSearchResult(t.TypedDict):
class ApiSearchResults (line 74) | class ApiSearchResults(t.TypedDict):
function request (line 86) | def request(query: str, params: dict[str, t.Any]):
function response (line 95) | def response(resp: SXNG_Response):
function init (line 112) | def init(engine_settings: dict[str, t.Any]):
FILE: searx/engines/mariadb_server.py
function init (line 63) | def init(engine_settings):
function search (line 75) | def search(query, params) -> EngineResults:
FILE: searx/engines/mastodon.py
function request (line 39) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/material_icons.py
function request (line 23) | def request(query, params):
function response (line 29) | def response(resp):
FILE: searx/engines/mediathekviewweb.py
function request (line 23) | def request(query, params):
function response (line 49) | def response(resp):
FILE: searx/engines/mediawiki.py
function request (line 103) | def request(query, params):
function response (line 134) | def response(resp):
FILE: searx/engines/meilisearch.py
function init (line 52) | def init(_):
function request (line 60) | def request(query, params):
function response (line 81) | def response(resp: SXNG_Response) -> EngineResults:
FILE: searx/engines/metacpan.py
function request (line 51) | def request(query, params):
function response (line 61) | def response(resp):
FILE: searx/engines/microsoft_learn.py
function request (line 37) | def request(query, params):
function response (line 61) | def response(resp) -> EngineResults:
FILE: searx/engines/mixcloud.py
function request (line 27) | def request(query, params):
function response (line 33) | def response(resp):
FILE: searx/engines/mojeek.py
function init (line 53) | def init(_):
function request (line 58) | def request(query, params):
function _general_results (line 83) | def _general_results(dom):
function _image_results (line 101) | def _image_results(dom):
function _news_results (line 118) | def _news_results(dom):
function response (line 133) | def response(resp):
function fetch_traits (line 148) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/mongodb.py
function init (line 72) | def init(_):
function connect (line 76) | def connect():
function search (line 86) | def search(query, params) -> EngineResults:
FILE: searx/engines/moviepilot.py
function request (line 49) | def request(query, params):
function response (line 85) | def response(resp):
FILE: searx/engines/mozhi.py
function request (line 28) | def request(_query, params):
function response (line 36) | def response(resp) -> EngineResults:
FILE: searx/engines/mrs.py
function init (line 40) | def init(engine_settings): # pylint: disable=unused-argument
function request (line 49) | def request(query, params):
function response (line 54) | def response(resp):
FILE: searx/engines/mwmbl.py
function request (line 30) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/mysql_server.py
function init (line 63) | def init(engine_settings):
function search (line 82) | def search(query, params) -> EngineResults:
FILE: searx/engines/naver.py
function init (line 70) | def init(_):
function request (line 75) | def request(query, params):
function response (line 91) | def response(resp) -> EngineResults:
function parse_general (line 97) | def parse_general(data):
function parse_images (line 123) | def parse_images(data):
function parse_news (line 147) | def parse_news(data):
function parse_videos (line 183) | def parse_videos(data):
FILE: searx/engines/niconico.py
function request (line 37) | def request(query, params):
function response (line 49) | def response(resp):
FILE: searx/engines/npm.py
function request (line 26) | def request(query: str, params):
function response (line 39) | def response(resp):
FILE: searx/engines/nvd.py
function request (line 23) | def request(query, params):
function response (line 39) | def response(resp) -> EngineResults:
FILE: searx/engines/nyaa.py
function request (line 42) | def request(query, params):
function response (line 55) | def response(resp):
FILE: searx/engines/odysee.py
function request (line 36) | def request(query, params):
function format_duration (line 65) | def format_duration(duration):
function response (line 73) | def response(resp):
function fetch_traits (line 112) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/ollama.py
function request (line 30) | def request(query, params):
function response (line 37) | def response(resp) -> EngineResults:
FILE: searx/engines/open_meteo.py
function request (line 42) | def request(query, params):
function _weather_data (line 111) | def _weather_data(location: weather.GeoLocation, data: dict[str, t.Any]):
function response (line 126) | def response(resp):
FILE: searx/engines/openalex.py
function request (line 123) | def request(query: str, params: "OnlineParams") -> None:
function response (line 152) | def response(resp: "SXNG_Response") -> EngineResults:
function _stringify_pages (line 190) | def _stringify_pages(biblio: dict[str, t.Any]) -> str:
function _parse_date (line 202) | def _parse_date(value: str | None) -> datetime | None:
function _doi_to_plain (line 214) | def _doi_to_plain(doi_value: str | None) -> str:
function _reconstruct_abstract (line 221) | def _reconstruct_abstract(
function _extract_links (line 242) | def _extract_links(item: dict[str, t.Any]) -> tuple[str, str, str]:
function _extract_authors (line 256) | def _extract_authors(item: dict[str, t.Any]) -> list[str]:
function _extract_tags (line 268) | def _extract_tags(item: dict[str, t.Any]) -> list[str]:
function _extract_biblio (line 277) | def _extract_biblio(
function _extract_comments (line 292) | def _extract_comments(item: dict[str, t.Any]) -> str:
FILE: searx/engines/openclipart.py
function request (line 23) | def request(query, params):
function response (line 32) | def response(resp):
FILE: searx/engines/openlibrary.py
function request (line 58) | def request(query: str, params: "OnlineParams") -> None:
function response (line 69) | def response(resp: "SXNG_Response") -> EngineResults:
function _parse_date (line 103) | def _parse_date(date: str) -> datetime | None:
FILE: searx/engines/opensemantic.py
function request (line 22) | def request(query, params):
function response (line 30) | def response(resp):
FILE: searx/engines/openstreetmap.py
function value_to_https_link (line 67) | def value_to_https_link(value):
function value_to_website_link (line 74) | def value_to_website_link(value):
function value_wikipedia_link (line 79) | def value_wikipedia_link(value):
function value_with_prefix (line 84) | def value_with_prefix(prefix, value):
function request (line 136) | def request(query, params):
function response (line 141) | def response(resp) -> EngineResults:
function get_wikipedia_image (line 205) | def get_wikipedia_image(raw_value):
function fetch_wikidata (line 211) | def fetch_wikidata(nominatim_json, user_language):
function get_title_address (line 260) | def get_title_address(result):
function get_url_osm_geojson (line 306) | def get_url_osm_geojson(result):
function get_img_src (line 326) | def get_img_src(result):
function get_links (line 349) | def get_links(result, user_language):
function get_data (line 375) | def get_data(result, user_language, ignore_keys):
function get_key_rank (line 401) | def get_key_rank(k):
function get_label (line 413) | def get_label(labels, lang):
function get_tag_label (line 431) | def get_tag_label(tag_category, tag_name, lang):
function get_key_label (line 438) | def get_key_label(key_name, lang):
FILE: searx/engines/openverse.py
function request (line 30) | def request(query, params):
function response (line 39) | def response(resp):
FILE: searx/engines/pdbe.py
function request (line 33) | def request(query, params):
function construct_body (line 41) | def construct_body(result):
function response (line 82) | def response(resp):
FILE: searx/engines/peertube.py
function request (line 50) | def request(query, params):
function response (line 87) | def response(resp):
function video_response (line 91) | def video_response(resp):
function fetch_traits (line 134) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/pexels.py
function init (line 49) | def init(engine_settings):
function _get_secret_key (line 54) | def _get_secret_key():
function request (line 81) | def request(query, params):
function response (line 107) | def response(resp):
FILE: searx/engines/photon.py
function request (line 35) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/pinterest.py
function request (line 21) | def request(query, params):
function response (line 39) | def response(resp):
FILE: searx/engines/piped.py
function _backend_url (line 96) | def _backend_url() -> str:
function _frontend_url (line 105) | def _frontend_url() -> str:
function request (line 111) | def request(query, params):
function response (line 130) | def response(resp):
FILE: searx/engines/piratebay.py
function request (line 47) | def request(query, params):
function response (line 56) | def response(resp):
FILE: searx/engines/pixabay.py
function request (line 34) | def request(query, params):
function _image_result (line 56) | def _image_result(result):
function _video_result (line 68) | def _video_result(result):
function response (line 82) | def response(resp):
FILE: searx/engines/pixiv.py
function request (line 27) | def request(query, params):
function response (line 46) | def response(resp):
FILE: searx/engines/pkg_go_dev.py
function request (line 40) | def request(query, params):
function response (line 51) | def response(resp):
FILE: searx/engines/podcastindex.py
function request (line 19) | def request(query, params):
function response (line 24) | def response(resp):
FILE: searx/engines/postgresql.py
function init (line 58) | def init(engine_settings):
function search (line 76) | def search(query, params) -> EngineResults:
function _fetch_results (line 86) | def _fetch_results(cur) -> EngineResults:
FILE: searx/engines/presearch.py
function init (line 101) | def init(_):
function _get_request_id (line 106) | def _get_request_id(query, params):
function request (line 151) | def request(query, params):
function _strip_leading_strings (line 160) | def _strip_leading_strings(text):
function _fix_title (line 167) | def _fix_title(title, url):
function parse_search_query (line 188) | def parse_search_query(json_results):
function response (line 248) | def response(resp):
FILE: searx/engines/public_domain_image_archive.py
function _clean_url (line 53) | def _clean_url(url):
function _get_algolia_api_url (line 60) | def _get_algolia_api_url():
function _clear_cached_api_url (line 86) | def _clear_cached_api_url():
function request (line 92) | def request(query, params):
function response (line 110) | def response(resp):
FILE: searx/engines/pubmed.py
function request (line 64) | def request(query: str, params: "OnlineParams") -> None:
function response (line 92) | def response(resp: "SXNG_Response") -> EngineResults: # pylint: disable...
FILE: searx/engines/pypi.py
function request (line 33) | def request(query, params):
function response (line 42) | def response(resp):
FILE: searx/engines/quark.py
function is_alibaba_captcha (line 35) | def is_alibaba_captcha(html):
function init (line 46) | def init(_):
function request (line 51) | def request(query, params):
function response (line 83) | def response(resp):
function parse_addition (line 162) | def parse_addition(data):
function parse_ai_page (line 170) | def parse_ai_page(data):
function parse_baike_sc (line 195) | def parse_baike_sc(data):
function parse_finance_shuidi (line 204) | def parse_finance_shuidi(data):
function parse_kk_yidian_all (line 227) | def parse_kk_yidian_all(data):
function parse_life_show_general_image (line 241) | def parse_life_show_general_image(data):
function parse_med_struct (line 264) | def parse_med_struct(data):
function parse_music_new_song (line 273) | def parse_music_new_song(data):
function parse_nature_result (line 287) | def parse_nature_result(data):
function parse_news_uchq (line 291) | def parse_news_uchq(data):
function parse_ss_doc (line 312) | def parse_ss_doc(data):
function parse_ss_note (line 353) | def parse_ss_note(data):
function parse_travel_dest_overview (line 367) | def parse_travel_dest_overview(data):
function parse_travel_ranking_list (line 375) | def parse_travel_ranking_list(data):
FILE: searx/engines/qwant.py
function request (line 110) | def request(query, params):
function response (line 151) | def response(resp):
function parse_web_lite (line 158) | def parse_web_lite(resp):
function parse_web_api (line 179) | def parse_web_api(resp):
function fetch_traits (line 321) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/radio_browser.py
function init (line 59) | def init(_):
function server_list (line 65) | def server_list() -> list[str]:
function request (line 90) | def request(query, params):
function response (line 123) | def response(resp):
function fetch_traits (line 170) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/recoll.py
function setup (line 79) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function search_after (line 96) | def search_after(time_range: str | None) -> str:
function request (line 103) | def request(query: str, params: "OnlineParams") -> None:
function response (line 114) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/reddit.py
function request (line 27) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/repology.py
function request (line 44) | def request(query: str, params: dict[str, t.Any]) -> None:
function _get_most_common (line 51) | def _get_most_common(items: list[str | None]) -> str | None:
function _flatten (line 62) | def _flatten(xss):
function response (line 66) | def response(resp: 'SXNG_Response') -> EngineResults:
FILE: searx/engines/reuters.py
function request (line 59) | def request(query, params):
function response (line 76) | def response(resp) -> EngineResults:
function resize_url (line 97) | def resize_url(thumbnail: dict[str, str], width: int = 0, height: int = ...
FILE: searx/engines/rottentomatoes.py
function request (line 30) | def request(query, params):
function response (line 35) | def response(resp):
FILE: searx/engines/rumble.py
function request (line 39) | def request(query, params):
function response (line 47) | def response(resp):
FILE: searx/engines/scanr_structures.py
function request (line 30) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/searx_engine.py
function request (line 27) | def request(query, params):
function response (line 47) | def response(resp):
FILE: searx/engines/selfhst.py
function request (line 20) | def request(query, params):
function response (line 26) | def response(resp):
FILE: searx/engines/semantic_scholar.py
function setup (line 60) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function get_ui_version (line 66) | def get_ui_version() -> str:
function request (line 83) | def request(query: str, params: "OnlineParams") -> None:
function response (line 106) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/senscritique.py
function request (line 63) | def request(query: str, params: dict[str, t.Any]) -> dict[str, t.Any]:
function response (line 80) | def response(resp) -> EngineResults:
function parse_item (line 97) | def parse_item(item: dict[str, t.Any]) -> MainResult | None:
function build_content_parts (line 120) | def build_content_parts(item: dict[str, t.Any], title: str, original_tit...
FILE: searx/engines/sepiasearch.py
function request (line 39) | def request(query, params):
function response (line 74) | def response(resp):
FILE: searx/engines/seznam.py
function request (line 29) | def request(query, params):
function response (line 47) | def response(resp):
FILE: searx/engines/sogou.py
function request (line 38) | def request(query, params):
function response (line 53) | def response(resp):
function _extract_url (line 83) | def _extract_url(url, item_html):
function _parse_date (line 92) | def _parse_date(text):
function _parse_results (line 104) | def _parse_results(item, item_html):
function _parse_results_with_image (line 117) | def _parse_results_with_image(item, item_html):
FILE: searx/engines/sogou_images.py
function request (line 24) | def request(query, params):
function response (line 34) | def response(resp):
FILE: searx/engines/sogou_videos.py
function request (line 25) | def request(query, params):
function response (line 36) | def response(resp):
FILE: searx/engines/sogou_wechat.py
function request (line 28) | def request(query, params):
function response (line 39) | def response(resp):
FILE: searx/engines/solidtorrents.py
function request (line 33) | def request(query, params):
function response (line 44) | def response(resp):
FILE: searx/engines/solr.py
function init (line 49) | def init(_):
function request (line 57) | def request(query, params):
function response (line 76) | def response(resp: SXNG_Response) -> EngineResults:
FILE: searx/engines/soundcloud.py
function request (line 57) | def request(query, params):
function response (line 82) | def response(resp):
function init (line 118) | def init(engine_settings): # pylint: disable=unused-argument
function get_client_id (line 123) | def get_client_id() -> str | None:
FILE: searx/engines/sourcehut.py
function request (line 62) | def request(query: str, params: "OnlineParams") -> None:
function response (line 71) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/spotify.py
function request (line 32) | def request(query, params):
function response (line 52) | def response(resp):
FILE: searx/engines/springer.py
function setup (line 94) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function request (line 108) | def request(query: str, params: "OnlineParams") -> None:
function response (line 120) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/sqlite.py
function init (line 69) | def init(engine_settings):
function sqlite_cursor (line 78) | def sqlite_cursor():
function search (line 96) | def search(query, params) -> EngineResults:
FILE: searx/engines/stackexchange.py
function request (line 32) | def request(query, params):
function response (line 49) | def response(resp):
FILE: searx/engines/startpage.py
function init (line 167) | def init(_):
function get_sc_code (line 179) | def get_sc_code(params):
function request (line 228) | def request(query, params):
function _parse_published_date (line 300) | def _parse_published_date(content: str) -> tuple[str, datetime | None]:
function _get_web_result (line 329) | def _get_web_result(result):
function _get_news_result (line 341) | def _get_news_result(result):
function _get_image_result (line 366) | def _get_image_result(result) -> dict[str, t.Any] | None:
function response (line 397) | def response(resp):
function fetch_traits (line 422) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/steam.py
function request (line 22) | def request(query, params):
function response (line 28) | def response(resp) -> EngineResults:
FILE: searx/engines/svgrepo.py
function request (line 25) | def request(query, params):
function response (line 30) | def response(resp):
FILE: searx/engines/tagesschau.py
function request (line 50) | def request(query, params):
function response (line 62) | def response(resp):
function _story (line 79) | def _story(item):
function _video (line 89) | def _video(item):
FILE: searx/engines/tineye.py
function request (line 57) | def request(query, params):
function parse_tineye_match (line 84) | def parse_tineye_match(match_json):
function response (line 152) | def response(resp) -> EngineResults:
FILE: searx/engines/tokyotoshokan.py
function request (line 31) | def request(query, params):
function response (line 38) | def response(resp):
FILE: searx/engines/tootfinder.py
function request (line 20) | def request(query, params):
function response (line 25) | def response(resp):
FILE: searx/engines/torznab.py
function init (line 86) | def init(engine_settings=None): # pylint: disable=unused-argument
function request (line 92) | def request(query: str, params: dict[str, t.Any]) -> dict[str, t.Any]:
function response (line 108) | def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
function build_result (line 127) | def build_result(item: etree.Element) -> dict[str, t.Any]:
function _map_result_url (line 171) | def _map_result_url(guid: str | None, comments: str | None) -> str | None:
function _map_leechers (line 179) | def _map_leechers(leechers: str | None, seeders: str | None, peers: str ...
function _map_published_date (line 187) | def _map_published_date(pubDate: str | None) -> datetime | None:
function _map_torrent_file (line 196) | def _map_torrent_file(link: str | None, enclosure_url: str | None) -> st...
function _map_magnet_link (line 204) | def _map_magnet_link(
function get_attribute (line 221) | def get_attribute(item: etree.Element, property_name: str) -> str | None:
function get_torznab_attribute (line 229) | def get_torznab_attribute(item: etree.Element, attribute_name: str) -> s...
FILE: searx/engines/translated.py
function request (line 27) | def request(query, params): # pylint: disable=unused-argument
function response (line 37) | def response(resp) -> EngineResults:
FILE: searx/engines/tubearchivist.py
function absolute_url (line 114) | def absolute_url(relative_url):
function init (line 118) | def init(_):
function request (line 125) | def request(query, params):
function response (line 136) | def response(resp) -> EngineResults:
function video_response (line 142) | def video_response(resp, results: EngineResults) -> None:
FILE: searx/engines/unsplash.py
function clean_url (line 26) | def clean_url(url):
function request (line 33) | def request(query, params):
function response (line 46) | def response(resp):
FILE: searx/engines/uxwing.py
function request (line 23) | def request(query, params):
function response (line 28) | def response(resp):
FILE: searx/engines/valkey_server.py
function init (line 56) | def init(_engine_settings):
function search (line 67) | def search(query, _params) -> EngineResults:
function search_keys (line 85) | def search_keys(query) -> list[dict]:
FILE: searx/engines/vimeo.py
function request (line 32) | def request(query, params):
function response (line 39) | def response(resp):
FILE: searx/engines/voidlinux.py
function request (line 38) | def request(query, params):
function response (line 50) | def response(resp):
FILE: searx/engines/wallhaven.py
function request (line 52) | def request(query, params):
function response (line 66) | def response(resp):
FILE: searx/engines/wikicommons.py
function setup (line 80) | def setup(engine_settings: dict[str, t.Any]) -> bool:
function request (line 94) | def request(query: str, params: "OnlineParams") -> None:
function response (line 120) | def response(resp: "SXNG_Response") -> EngineResults:
FILE: searx/engines/wikidata.py
class WDAttribute (line 147) | class WDAttribute:
method __init__ (line 149) | def __init__(self, name: str):
method get_select (line 152) | def get_select(self):
method get_label (line 155) | def get_label(self, language: str):
method get_where (line 158) | def get_where(self):
method get_wikibase_label (line 161) | def get_wikibase_label(self) -> str:
method get_group_by (line 164) | def get_group_by(self) -> str:
method get_str (line 167) | def get_str(self, result: dict[str, t.Any], language: str) -> str | No...
method __repr__ (line 170) | def __repr__(self):
class WDAmountAttribute (line 174) | class WDAmountAttribute(WDAttribute):
method get_select (line 175) | def get_select(self) -> str:
method get_where (line 178) | def get_where(self):
method get_group_by (line 185) | def get_group_by(self) -> str:
method get_str (line 188) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
class WDArticle (line 197) | class WDArticle(WDAttribute):
method __init__ (line 199) | def __init__(self, language: str, kwargs: dict[str, t.Any] | None = No...
method get_label (line 204) | def get_label(self, language: str):
method get_select (line 208) | def get_select(self):
method get_where (line 211) | def get_where(self):
method get_group_by (line 219) | def get_group_by(self):
method get_str (line 222) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
class WDLabelAttribute (line 227) | class WDLabelAttribute(WDAttribute):
method get_select (line 228) | def get_select(self):
method get_where (line 231) | def get_where(self):
method get_wikibase_label (line 234) | def get_wikibase_label(self) -> str:
method get_str (line 237) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
class WDURLAttribute (line 241) | class WDURLAttribute(WDAttribute):
method __init__ (line 245) | def __init__(
method get_str (line 276) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
class WDGeoAttribute (line 296) | class WDGeoAttribute(WDAttribute):
method get_label (line 297) | def get_label(self, language: str):
method get_select (line 300) | def get_select(self):
method get_where (line 303) | def get_where(self):
method get_group_by (line 310) | def get_group_by(self):
method get_str (line 313) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
method get_geo_url (line 320) | def get_geo_url(self, result: dict[str, t.Any], osm_zoom: int = 19) ->...
class WDImageAttribute (line 328) | class WDImageAttribute(WDURLAttribute):
method __init__ (line 330) | def __init__(self, name: str, url_id: str | None = None, priority: int...
class WDDateAttribute (line 335) | class WDDateAttribute(WDAttribute):
method get_select (line 336) | def get_select(self):
method get_where (line 339) | def get_where(self):
method get_group_by (line 353) | def get_group_by(self):
method format_8 (line 356) | def format_8(self, value: str, locale: str) -> str: # pylint: disable...
method format_9 (line 360) | def format_9(self, value: str, locale: str) -> str:
method format_10 (line 370) | def format_10(self, value: str, locale: str) -> str:
method format_11 (line 375) | def format_11(self, value: str, locale: str) -> str:
method format_13 (line 380) | def format_13(self, value: str, locale: str) -> str:
method format_14 (line 390) | def format_14(self, value: str, locale: str) -> str:
method get_str (line 412) | def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
function get_headers (line 447) | def get_headers() -> dict[str, str]:
function get_label_for_entity (line 455) | def get_label_for_entity(entity_id: str, language: str) -> str:
function send_wikidata_query (line 468) | def send_wikidata_query(query: str, method: str = "GET", **kwargs: dict[...
function request (line 482) | def request(query: str, params: "OnlineParams") -> None:
function response (line 499) | def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
function get_thumbnail (line 527) | def get_thumbnail(img_src: str | None) -> str | None:
function get_results (line 566) | def get_results(
function get_query (line 654) | def get_query(query: str, language: str) -> tuple[str, WDAttrList]:
function get_attributes (line 671) | def get_attributes(language: str):
function debug_explain_wikidata_query (line 818) | def debug_explain_wikidata_query(query: str, method: str = "GET"):
function init (line 827) | def init(_):
function init_wikidata_properties (line 833) | def init_wikidata_properties():
function fetch_traits (line 865) | def fetch_traits(engine_traits: EngineTraits):
FILE: searx/engines/wikipedia.py
function get_wiki_params (line 136) | def get_wiki_params(sxng_locale, eng_traits):
function request (line 147) | def request(query, params):
function response (line 163) | def response(resp):
function fetch_traits (line 239) | def fetch_traits(engine_traits: EngineTraits):
function fetch_wikimedia_traits (line 244) | def fetch_wikimedia_traits(engine_traits: EngineTraits):
FILE: searx/engines/wolframalpha_api.py
function request (line 42) | def request(query, params):
function replace_pua_chars (line 50) | def replace_pua_chars(text):
function response (line 70) | def response(resp):
FILE: searx/engines/wolframalpha_noapi.py
function init (line 54) | def init(engine_settings):
function obtain_token (line 59) | def obtain_token() -> str:
function request (line 69) | def request(query, params):
function response (line 77) | def response(resp):
FILE: searx/engines/wordnik.py
function request (line 23) | def request(query, params):
function response (line 28) | def response(resp):
FILE: searx/engines/wttr.py
function request (line 78) | def request(query, params):
function _weather_data (line 85) | def _weather_data(location: weather.GeoLocation, data: dict[str, t.Any]):
function response (line 103) | def response(resp):
FILE: searx/engines/www1x.py
function request (line 30) | def request(query, params):
function response (line 37) | def response(resp):
FILE: searx/engines/xpath.py
function request (line 225) | def request(query, params):
function response (line 266) | def response(resp) -> EngineResults: # pylint: disable=too-many-branches
FILE: searx/engines/yacy.py
function init (line 105) | def init(_):
function _base_url (line 115) | def _base_url() -> str:
function request (line 126) | def request(query, params):
function response (line 149) | def response(resp):
FILE: searx/engines/yahoo.py
function build_sb_cookie (line 123) | def build_sb_cookie(cookie_params):
function request (line 144) | def request(query, params):
function parse_url (line 196) | def parse_url(url_string):
function response (line 215) | def response(resp):
FILE: searx/engines/yahoo_news.py
function request (line 59) | def request(query, params):
function response (line 67) | def response(resp):
FILE: searx/engines/yandex.py
function catch_bad_response (line 51) | def catch_bad_response(resp):
function request (line 56) | def request(query, params):
function response (line 88) | def response(resp):
FILE: searx/engines/yandex_music.py
function request (line 35) | def request(query, params):
function response (line 43) | def response(resp):
FILE: searx/engines/yep.py
function request (line 39) | def request(query: str, params: 'OnlineParams') -> None:
function response (line 51) | def response(resp: 'SXNG_Response') -> EngineResults:
function fetch_traits (line 66) | def fetch_traits(engine_traits: 'EngineTraits'):
FILE: searx/engines/youtube_api.py
function request (line 34) | def request(query, params):
function response (line 45) | def response(resp):
FILE: searx/engines/youtube_noapi.py
function request (line 38) | def request(query, params):
function response (line 59) | def response(resp):
function parse_next_page_response (line 65) | def parse_next_page_response(response_text):
function parse_first_page_response (line 110) | def parse_first_page_response(response_text):
function get_text_from_json (line 167) | def get_text_from_json(element):
FILE: searx/engines/zlibrary.py
function setup (line 84) | def setup(engine_settings: dict[str, t.Any]) -> bool: # pylint: disable...
function request (line 97) | def request(query: str, params: "OnlineParams") -> None:
function response (line 118) | def response(resp: "SXNG_Response") -> EngineResults:
function domain_is_seized (line 132) | def domain_is_seized(dom: ElementType):
function _text (line 136) | def _text(item: ElementType, selector: str) -> str | None:
function _parse_result (line 140) | def _parse_result(item: ElementType) -> dict[str, t.Any]:
function fetch_traits (line 184) | def fetch_traits(engine_traits: EngineTraits) -> None:
FILE: searx/exceptions.py
class SearxException (line 10) | class SearxException(Exception):
class SearxParameterException (line 14) | class SearxParameterException(SearxException):
method __init__ (line 17) | def __init__(self, name: str, value: t.Any):
class SearxSettingsException (line 29) | class SearxSettingsException(SearxException):
method __init__ (line 32) | def __init__(self, message: str | Exception, filename: str | None):
class SearxEngineException (line 38) | class SearxEngineException(SearxException):
class SearxXPathSyntaxException (line 42) | class SearxXPathSyntaxException(SearxEngineException):
method __init__ (line 45) | def __init__(self, xpath_spec: "str | XPath", message: str):
class SearxEngineResponseException (line 52) | class SearxEngineResponseException(SearxEngineException):
class SearxEngineAPIException (line 56) | class SearxEngineAPIException(SearxEngineResponseException):
class SearxEngineAccessDeniedException (line 60) | class SearxEngineAccessDeniedException(SearxEngineResponseException):
method __init__ (line 67) | def __init__(self, suspended_time: int | None = None, message: str = '...
method _get_default_suspended_time (line 82) | def _get_default_suspended_time(self) -> int:
class SearxEngineCaptchaException (line 88) | class SearxEngineCaptchaException(SearxEngineAccessDeniedException):
method __init__ (line 95) | def __init__(self, suspended_time: int | None = None, message: str = '...
class SearxEngineTooManyRequestsException (line 99) | class SearxEngineTooManyRequestsException(SearxEngineAccessDeniedExcepti...
method __init__ (line 109) | def __init__(self, suspended_time: int | None = None, message: str = '...
class SearxEngineXPathException (line 113) | class SearxEngineXPathException(SearxEngineResponseException):
method __init__ (line 116) | def __init__(self, xpath_spec: "str | XPath", message: str):
FILE: searx/extended_types.py
class SXNG_Request (line 36) | class SXNG_Request(flask.Request):
class SXNG_Response (line 72) | class SXNG_Response(httpx.Response):
FILE: searx/external_bang.py
function get_node (line 17) | def get_node(external_bangs_db: dict[str, t.Any], bang: str):
function get_bang_definition_and_ac (line 30) | def get_bang_definition_and_ac(external_bangs_db: dict[str, t.Any], bang...
function resolve_bang_definition (line 49) | def resolve_bang_definition(bang_definition: str, query: str) -> tuple[s...
function get_bang_definition_and_autocomplete (line 64) | def get_bang_definition_and_autocomplete(
function get_bang_url (line 93) | def get_bang_url(search_query: "SearchQuery", external_bangs_db: dict[st...
FILE: searx/external_urls.py
function get_imdb_url_id (line 19) | def get_imdb_url_id(imdb_item_id: str):
function get_wikimedia_image_id (line 24) | def get_wikimedia_image_id(url: str):
function get_external_url (line 32) | def get_external_url(url_id: str, item_id: str | None, alternative: str ...
function get_earth_coordinates_url (line 56) | def get_earth_coordinates_url(latitude, longitude, osm_zoom, alternative...
function area_to_osm_zoom (line 66) | def area_to_osm_zoom(area):
FILE: searx/favicons/__init__.py
function is_active (line 22) | def is_active():
function init (line 26) | def init():
FILE: searx/favicons/cache.py
function state (line 46) | def state():
function maintenance (line 52) | def maintenance(force: bool = True, debug: bool = False):
function init (line 72) | def init(cfg: "FaviconCacheConfig"):
class FaviconCacheConfig (line 93) | class FaviconCacheConfig(msgspec.Struct): # pylint: disable=too-few-pub...
class FaviconCacheStats (line 142) | class FaviconCacheStats:
method __sub__ (line 157) | def __sub__(self, other: "FaviconCacheStats") -> "FaviconCacheStats":
method report (line 171) | def report(self, fmt: str = "{descr}: {val}\n"):
class FaviconCache (line 183) | class FaviconCache(abc.ABC):
method __init__ (line 187) | def __init__(self, cfg: FaviconCacheConfig):
method __call__ (line 191) | def __call__(self, resolver: str, authority: str) -> None | tuple[None...
method set (line 197) | def set(self, resolver: str, authority: str, mime: str | None, data: b...
method state (line 202) | def state(self) -> FaviconCacheStats:
method maintenance (line 207) | def maintenance(self, force: bool = False):
class FaviconCacheNull (line 212) | class FaviconCacheNull(FaviconCache):
method __init__ (line 219) | def __init__(self, cfg: FaviconCacheConfig):
method __call__ (line 222) | def __call__(self, resolver: str, authority: str) -> None | tuple[None...
method set (line 225) | def set(self, resolver: str, authority: str, mime: str | None, data: b...
method state (line 228) | def state(self):
method maintenance (line 231) | def maintenance(self, force: bool = False):
class FaviconCacheSQLite (line 236) | class FaviconCacheSQLite(sqlitedb.SQLiteAppl, FaviconCache): # pyright:...
method __init__ (line 312) | def __init__(self, cfg: FaviconCacheConfig):
method __call__ (line 320) | def __call__(self, resolver: str, authority: str) -> None | tuple[None...
method set (line 338) | def set(self, resolver: str, authority: str, mime: str | None, data: b...
method next_maintenance_time (line 376) | def next_maintenance_time(self) -> int:
method maintenance (line 381) | def maintenance(self, force: bool = False):
method _query_val (line 429) | def _query_val(self, sql: str, default: t.Any = None):
method state (line 437) | def state(self) -> FaviconCacheStats:
class FaviconCacheMEM (line 447) | class FaviconCacheMEM(FaviconCache):
method __init__ (line 457) | def __init__(self, cfg: FaviconCacheConfig):
method __call__ (line 463) | def __call__(self, resolver: str, authority: str) -> None | tuple[byte...
method set (line 473) | def set(self, resolver: str, authority: str, mime: str | None, data: b...
method state (line 492) | def state(self):
method maintenance (line 495) | def maintenance(self, force: bool = False):
FILE: searx/favicons/config.py
class FaviconConfig (line 20) | class FaviconConfig(msgspec.Struct): # pylint: disable=too-few-public-m...
method from_toml_file (line 36) | def from_toml_file(cls, cfg_file: pathlib.Path, use_cache: bool) -> "F...
class _FaviconConfig (line 62) | class _FaviconConfig(msgspec.Struct): # pylint: disable=too-few-public-...
FILE: searx/favicons/proxy.py
function init (line 29) | def init(cfg: "FaviconProxyConfig"):
function _initial_resolver_map (line 34) | def _initial_resolver_map():
class FaviconProxyConfig (line 44) | class FaviconProxyConfig(msgspec.Struct):
method get_resolver (line 68) | def get_resolver(self, name: str) -> Callable | None:
method favicon (line 86) | def favicon(self, **replacements):
method favicon_data_url (line 93) | def favicon_data_url(self, **replacements):
function favicon_proxy (line 112) | def favicon_proxy():
function search_favicon (line 159) | def search_favicon(resolver: str, authority: str) -> tuple[None | bytes,...
function favicon_url (line 195) | def favicon_url(authority: str) -> str:
FILE: searx/favicons/resolvers.py
function _req_args (line 20) | def _req_args(**kwargs):
function allesedv (line 27) | def allesedv(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
function duckduckgo (line 43) | def duckduckgo(domain: str, timeout: int) -> tuple[None | bytes, None | ...
function google (line 58) | def google(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
function yandex (line 79) | def yandex(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
FILE: searx/flaskfix.py
class ReverseProxyPathFix (line 11) | class ReverseProxyPathFix:
method __init__ (line 33) | def __init__(self, wsgi_app):
method __call__ (line 54) | def __call__(self, environ, start_response):
function patch_application (line 72) | def patch_application(app):
FILE: searx/infopage/__init__.py
function __getattr__ (line 45) | def __getattr__(name: str):
class InfoPage (line 54) | class InfoPage:
method __init__ (line 57) | def __init__(self, fname: str):
method raw_content (line 61) | def raw_content(self):
method content (line 67) | def content(self):
method title (line 74) | def title(self):
method html (line 83) | def html(self) -> str:
method get_ctx (line 94) | def get_ctx(self) -> dict[str, str]:
method __repr__ (line 113) | def __repr__(self):
class InfoPageSet (line 117) | class InfoPageSet: # pylint: disable=too-few-public-methods
method __init__ (line 127) | def __init__(self, page_class: type[InfoPage] | None = None, info_fold...
method get_page (line 149) | def get_page(self, pagename: str, locale: str | None = None):
method iter_pages (line 184) | def iter_pages(self, locale: str | None = None, fallback_to_default: b...
FILE: searx/limiter.py
function get_cfg (line 133) | def get_cfg() -> config.Config:
function filter_request (line 147) | def filter_request(request: SXNG_Request) -> werkzeug.Response | None:
function pre_request (line 212) | def pre_request():
function is_installed (line 217) | def is_installed():
function initialize (line 222) | def initialize(app: flask.Flask, settings):
FILE: searx/locales.py
function localeselector (line 86) | def localeselector():
function get_translations (line 110) | def get_translations():
function get_translation_locales (line 123) | def get_translation_locales() -> list[str]:
function locales_initialize (line 142) | def locales_initialize():
function region_tag (line 153) | def region_tag(locale: babel.Locale) -> str:
function language_tag (line 160) | def language_tag(locale: babel.Locale) -> str:
function get_locale (line 170) | def get_locale(locale_tag: str) -> babel.Locale | None:
function get_official_locales (line 181) | def get_official_locales(
function get_engine_locale (line 218) | def get_engine_locale(searxng_locale: str, engine_locales: dict[str, str...
function match_locale (line 372) | def match_locale(searxng_locale: str, locale_tag_list: list[str], fallba...
function build_engine_locales (line 421) | def build_engine_locales(tag_list: list[str]) -> dict[str, str]:
FILE: searx/metrics/__init__.py
function histogram_observe_time (line 36) | def histogram_observe_time(*args):
function histogram_observe (line 47) | def histogram_observe(duration, *args):
function histogram (line 51) | def histogram(*args, raise_on_not_found=True):
function counter_inc (line 58) | def counter_inc(*args: str):
function counter_add (line 62) | def counter_add(value: int, *args: str):
function counter (line 66) | def counter(*args):
function initialize (line 70) | def initialize(engine_names: list[str] | None = None, enabled: bool = Tr...
function get_engine_errors (line 111) | def get_engine_errors(engline_name_list):
function get_reliabilities (line 142) | def get_reliabilities(engline_name_list):
function get_engines_stats (line 166) | def get_engines_stats(engine_name_list: list[str]):
function openmetrics (line 243) | def openmetrics(engine_stats, engine_reliabilities):
FILE: searx/metrics/error_recorder.py
class ErrorContext (line 25) | class ErrorContext: # pylint: disable=missing-class-docstring
method __init__ (line 27) | def __init__( # pylint: disable=too-many-arguments
method __eq__ (line 47) | def __eq__(self, o) -> bool: # pylint: disable=invalid-name
method __hash__ (line 61) | def __hash__(self):
method __repr__ (line 75) | def __repr__(self):
function add_error_context (line 87) | def add_error_context(engine_name: str, error_context: ErrorContext) -> ...
function get_trace (line 93) | def get_trace(traces):
function get_hostname (line 103) | def get_hostname(exc: HTTPError) -> str | None:
function get_request_exception_messages (line 110) | def get_request_exception_messages(
function get_messages (line 131) | def get_messages(exc, filename) -> tuple[str, ...]: # pylint: disable=t...
function get_exception_classname (line 151) | def get_exception_classname(exc: BaseException) -> str:
function get_error_context (line 160) | def get_error_context(
function count_exception (line 174) | def count_exception(engine_name: str, exc: BaseException, secondary: boo...
function count_error (line 187) | def count_error(
FILE: searx/metrics/models.py
class Histogram (line 17) | class Histogram: # pylint: disable=missing-class-docstring
method __init__ (line 21) | def __init__(self, width=10, size=200):
method observe (line 29) | def observe(self, value):
method quartiles (line 43) | def quartiles(self):
method count (line 47) | def count(self):
method sum (line 51) | def sum(self):
method average (line 55) | def average(self):
method quartile_percentage (line 62) | def quartile_percentage(self):
method quartile_percentage_map (line 70) | def quartile_percentage_map(self):
method percentage (line 85) | def percentage(self, percentage):
method __repr__ (line 100) | def __repr__(self):
class HistogramStorage (line 104) | class HistogramStorage: # pylint: disable=missing-class-docstring
method __init__ (line 108) | def __init__(self, histogram_class=Histogram):
method clear (line 112) | def clear(self):
method configure (line 115) | def configure(self, width, size, *args):
method get (line 120) | def get(self, *args):
method dump (line 123) | def dump(self):
class CounterStorage (line 130) | class CounterStorage: # pylint: disable=missing-class-docstring
method __init__ (line 134) | def __init__(self):
method clear (line 138) | def clear(self):
method configure (line 142) | def configure(self, *args: str):
method get (line 146) | def get(self, *args: str):
method add (line 149) | def add(self, value: int, *args: str):
method dump (line 153) | def dump(self):
class VoidHistogram (line 161) | class VoidHistogram(Histogram): # pylint: disable=missing-class-docstring
method observe (line 162) | def observe(self, value):
class VoidCounterStorage (line 166) | class VoidCounterStorage(CounterStorage): # pylint: disable=missing-cla...
method add (line 167) | def add(self, value, *args):
FILE: searx/network/__init__.py
function reset_time_for_thread (line 32) | def reset_time_for_thread():
function get_time_for_thread (line 36) | def get_time_for_thread() -> float | None:
function set_timeout_for_thread (line 41) | def set_timeout_for_thread(timeout: float, start_time: float | None = No...
function set_context_network_name (line 46) | def set_context_network_name(network_name: str):
function get_context_network (line 50) | def get_context_network() -> "Network":
function _record_http_time (line 59) | def _record_http_time():
function _get_timeout (line 73) | def _get_timeout(start_time: float, kwargs: t.Any) -> float:
function request (line 96) | def request(method: str, url: str, **kwargs: t.Any) -> SXNG_Response:
function multi_requests (line 111) | def multi_requests(request_list: list["Request"]) -> list[httpx.Response...
class Request (line 137) | class Request(t.NamedTuple):
method get (line 145) | def get(url: str, **kwargs: t.Any):
method options (line 149) | def options(url: str, **kwargs: t.Any):
method head (line 153) | def head(url: str, **kwargs: t.Any):
method post (line 157) | def post(url: str, **kwargs: t.Any):
method put (line 161) | def put(url: str, **kwargs: t.Any):
method patch (line 165) | def patch(url: str, **kwargs: t.Any):
method delete (line 169) | def delete(url: str, **kwargs: t.Any):
function get (line 173) | def get(url: str, **kwargs: t.Any) -> SXNG_Response:
function options (line 178) | def options(url: str, **kwargs: t.Any) -> SXNG_Response:
function head (line 183) | def head(url: str, **kwargs: t.Any) -> SXNG_Response:
function post (line 188) | def post(url: str, data: dict[str, t.Any] | None = None, **kwargs: t.Any...
function put (line 192) | def put(url: str, data: dict[str, t.Any] | None = None, **kwargs: t.Any)...
function patch (line 196) | def patch(url: str, data: dict[str, t.Any] | None = None, **kwargs: t.An...
function delete (line 200) | def delete(url: str, **kwargs: t.Any) -> SXNG_Response:
function stream_chunk_to_queue (line 204) | async def stream_chunk_to_queue(network, queue, method: str, url: str, *...
function _stream_generator (line 230) | def _stream_generator(method: str, url: str, **kwargs: t.Any):
function _close_response_method (line 245) | def _close_response_method(self):
function stream (line 255) | def stream(method: str, url: str, **kwargs: t.Any) -> tuple[SXNG_Respons...
FILE: searx/network/client.py
function shuffle_ciphers (line 28) | def shuffle_ciphers(ssl_context: SSLContext):
function get_sslcontexts (line 51) | def get_sslcontexts(
class AsyncHTTPTransportNoHttp (line 61) | class AsyncHTTPTransportNoHttp(httpx.AsyncHTTPTransport):
method __init__ (line 74) | def __init__(self, *args, **kwargs): # type: ignore
method handle_async_request (line 79) | async def handle_async_request(self, request: httpx.Request):
method aclose (line 82) | async def aclose(self) -> None:
method __aenter__ (line 85) | async def __aenter__(self):
method __aexit__ (line 88) | async def __aexit__(
class AsyncProxyTransportFixed (line 97) | class AsyncProxyTransportFixed(AsyncProxyTransport):
method handle_async_request (line 103) | async def handle_async_request(self, request: httpx.Request):
function get_transport_for_socks_proxy (line 114) | def get_transport_for_socks_proxy(
function get_transport (line 145) | def get_transport(
function new_client (line 160) | def new_client(
function get_loop (line 209) | def get_loop() -> asyncio.AbstractEventLoop:
function init (line 213) | def init():
FILE: searx/network/network.py
class Network (line 45) | class Network:
method __init__ (line 68) | def __init__(
method check_parameters (line 104) | def check_parameters(self):
method iter_ipaddresses (line 114) | def iter_ipaddresses(self) -> Generator[str]:
method get_ipaddress_cycle (line 122) | def get_ipaddress_cycle(self):
method iter_proxies (line 137) | def iter_proxies(self) -> Generator[tuple[str, list[str]]]:
method get_proxy_cycles (line 150) | def get_proxy_cycles(self) -> Generator[tuple[tuple[str, str], ...], s...
method log_response (line 158) | async def log_response(self, response: httpx.Response):
method check_tor_proxy (line 167) | async def check_tor_proxy(client: httpx.AsyncClient, proxies) -> bool:
method get_client (line 190) | async def get_client(self, verify: bool | None = None, max_redirects: ...
method aclose (line 217) | async def aclose(self):
method extract_kwargs_clients (line 227) | def extract_kwargs_clients(kwargs: dict[str, t.Any]) -> dict[str, t.Any]:
method extract_do_raise_for_httperror (line 239) | def extract_do_raise_for_httperror(kwargs: dict[str, t.Any]):
method patch_response (line 246) | def patch_response(self, response: httpx.Response, do_raise_for_httper...
method is_valid_response (line 262) | def is_valid_response(self, response: httpx.Response):
method call_client (line 272) | async def call_client(self, stream: bool, method: str, url: str, **kwa...
method request (line 303) | async def request(self, method: str, url: str, **kwargs: t.Any) -> SXN...
method stream (line 306) | async def stream(self, method: str, url: str, **kwargs):
method aclose_all (line 310) | async def aclose_all(cls):
function get_network (line 314) | def get_network(name: str | None = None) -> "Network":
function check_network_configuration (line 318) | def check_network_configuration():
function initialize (line 329) | def initialize(
function done (line 417) | def done():
FILE: searx/network/raise_for_httperror.py
function is_cloudflare_challenge (line 16) | def is_cloudflare_challenge(resp: "SXNG_Response"):
function is_cloudflare_firewall (line 29) | def is_cloudflare_firewall(resp: "SXNG_Response"):
function raise_for_cloudflare_captcha (line 33) | def raise_for_cloudflare_captcha(resp: "SXNG_Response"):
function raise_for_recaptcha (line 49) | def raise_for_recaptcha(resp: "SXNG_Response"):
function raise_for_captcha (line 56) | def raise_for_captcha(resp: "SXNG_Response"):
function raise_for_httperror (line 61) | def raise_for_httperror(resp: "SXNG_Response") -> None:
FILE: searx/openmetrics.py
class OpenMetricsFamily (line 11) | class OpenMetricsFamily: # pylint: disable=too-few-public-methods
method __init__ (line 31) | def __init__(
method __str__ (line 40) | def __str__(self):
FILE: searx/plugins/__init__.py
function initialize (line 107) | def initialize(app):
FILE: searx/plugins/_core.py
class PluginInfo (line 28) | class PluginInfo:
class Plugin (line 68) | class Plugin(abc.ABC):
method __init__ (line 92) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method __hash__ (line 115) | def __hash__(self) -> int:
method __eq__ (line 123) | def __eq__(self, other: t.Any):
method init (line 129) | def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-...
method pre_search (line 141) | def pre_search(self, request: SXNG_Request, search: "SearchWithPlugins...
method on_result (line 149) | def on_result(self, request: SXNG_Request, search: "SearchWithPlugins"...
method post_search (line 169) | def post_search(
class PluginCfg (line 179) | class PluginCfg:
class PluginStorage (line 192) | class PluginStorage:
method __init__ (line 198) | def __init__(self):
method __iter__ (line 201) | def __iter__(self) -> Generator[Plugin]:
method __len__ (line 204) | def __len__(self):
method info (line 208) | def info(self) -> list[PluginInfo]:
method load_settings (line 212) | def load_settings(self, cfg: dict[str, dict[str, t.Any]]):
method register (line 231) | def register(self, plugin: Plugin):
method init (line 244) | def init(self, app: "flask.Flask") -> None:
method pre_search (line 253) | def pre_search(self, request: SXNG_Request, search: "SearchWithPlugins...
method on_result (line 267) | def on_result(self, request: SXNG_Request, search: "SearchWithPlugins"...
method post_search (line 282) | def post_search(self, request: SXNG_Request, search: "SearchWithPlugin...
FILE: searx/plugins/ahmia_filter.py
class SXNGPlugin (line 24) | class SXNGPlugin(Plugin):
method __init__ (line 29) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method on_result (line 38) | def on_result(
method init (line 46) | def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-...
FILE: searx/plugins/calculator.py
class SXNGPlugin (line 15) | class SXNGPlugin(Plugin):
method __init__ (line 20) | def __init__(self, plg_cfg: "PluginCfg") -> None:
FILE: searx/plugins/hash_plugin.py
class SXNGPlugin (line 19) | class SXNGPlugin(Plugin):
method __init__ (line 27) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method post_search (line 41) | def post_search(self, request: "SXNG_Request", search: "SearchWithPlug...
FILE: searx/plugins/hostnames.py
class SXNGPlugin (line 110) | class SXNGPlugin(Plugin):
method __init__ (line 115) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method on_result (line 124) | def on_result(self, request: "SXNG_Request", search: "SearchWithPlugin...
method init (line 147) | def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-...
method _load_regular_expressions (line 161) | def _load_regular_expressions(self, settings_key) -> dict[re.Pattern, ...
function filter_url_field (line 180) | def filter_url_field(result: "Result|LegacyResult", field_name: str, url...
FILE: searx/plugins/infinite_scroll.py
class SXNGPlugin (line 15) | class SXNGPlugin(Plugin):
method __init__ (line 20) | def __init__(self, plg_cfg: "PluginCfg") -> None:
FILE: searx/plugins/oa_doi_rewrite.py
function filter_url_field (line 25) | def filter_url_field(result: "Result|LegacyResult", field_name: str, url...
class SXNGPlugin (line 45) | class SXNGPlugin(Plugin):
method __init__ (line 50) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method on_result (line 59) | def on_result(
function extract_doi (line 73) | def extract_doi(url):
function get_doi_resolver (line 84) | def get_doi_resolver() -> str:
FILE: searx/plugins/self_info.py
class SXNGPlugin (line 20) | class SXNGPlugin(Plugin):
method __init__ (line 29) | def __init__(self, plg_cfg: "PluginCfg"):
method post_search (line 44) | def post_search(self, request: "SXNG_Request", search: "SearchWithPlug...
FILE: searx/plugins/time_zone.py
class SXNGPlugin (line 21) | class SXNGPlugin(Plugin):
method __init__ (line 28) | def __init__(self, plg_cfg: "PluginCfg"):
method post_search (line 39) | def post_search(self, request: "SXNG_Request", search: "SearchWithPlug...
FILE: searx/plugins/tor_check.py
class SXNGPlugin (line 31) | class SXNGPlugin(Plugin):
method __init__ (line 37) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method post_search (line 49) | def post_search(self, request: "SXNG_Request", search: "SearchWithPlug...
FILE: searx/plugins/tracker_url_remover.py
class SXNGPlugin (line 25) | class SXNGPlugin(Plugin):
method __init__ (line 30) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method init (line 40) | def init(self, app: "flask.Flask") -> bool:
method on_result (line 44) | def on_result(self, request: "SXNG_Request", search: "SearchWithPlugin...
method filter_url_field (line 50) | def filter_url_field(cls, result: "Result|LegacyResult", field_name: s...
FILE: searx/plugins/unit_converter.py
class SXNGPlugin (line 30) | class SXNGPlugin(Plugin):
method __init__ (line 37) | def __init__(self, plg_cfg: "PluginCfg") -> None:
method post_search (line 47) | def post_search(self, request: "SXNG_Request", search: "SearchWithPlug...
function _parse_text_and_convert (line 82) | def _parse_text_and_convert(from_query, to_query) -> str | None:
FILE: searx/preferences.py
class ValidationException (line 44) | class ValidationException(Exception):
class Setting (line 48) | class Setting:
method __init__ (line 51) | def __init__(self, default_value: t.Any, locked: bool = False):
method parse (line 56) | def parse(self, data: str):
method get_value (line 63) | def get_value(self):
method save (line 70) | def save(self, name: str, resp: flask.Response):
class StringSetting (line 77) | class StringSetting(Setting):
class EnumStringSetting (line 81) | class EnumStringSetting(Setting):
method __init__ (line 86) | def __init__(self, default_value: str, choices: Iterable[str], locked:...
method _validate_selection (line 91) | def _validate_selection(self, selection: str):
method parse (line 95) | def parse(self, data: str):
class MultipleChoiceSetting (line 101) | class MultipleChoiceSetting(Setting):
method __init__ (line 104) | def __init__(self, default_value: list[str], choices: Iterable[str], l...
method _validate_selections (line 109) | def _validate_selections(self, selections: list[str]):
method parse (line 114) | def parse(self, data: str):
method parse_form (line 124) | def parse_form(self, data: list[str]):
method save (line 133) | def save(self, name: str, resp: flask.Response):
class SetSetting (line 138) | class SetSetting(Setting):
method __init__ (line 141) | def __init__(self, *args, **kwargs): # type: ignore
method get_value (line 145) | def get_value(self):
method parse (line 149) | def parse(self, data: str):
method parse_form (line 159) | def parse_form(self, data: str):
method save (line 166) | def save(self, name: str, resp: flask.Response):
class SearchLanguageSetting (line 171) | class SearchLanguageSetting(EnumStringSetting):
method _validate_selection (line 176) | def _validate_selection(self, selection: str):
method parse (line 180) | def parse(self, data: str):
class MapSetting (line 197) | class MapSetting(Setting):
method __init__ (line 203) | def __init__(
method parse (line 212) | def parse(self, data: str):
method save (line 220) | def save(self, name: str, resp: flask.Response):
class BooleanSetting (line 226) | class BooleanSetting(Setting):
method normalized_str (line 232) | def normalized_str(self, val: t.Any) -> str:
method parse (line 238) | def parse(self, data: str):
method save (line 243) | def save(self, name: str, resp: flask.Response):
class BooleanChoices (line 249) | class BooleanChoices:
method __init__ (line 252) | def __init__(self, name: str, choices: dict[str, bool], locked: bool =...
method transform_form_items (line 258) | def transform_form_items(self, items):
method transform_values (line 261) | def transform_values(self, values):
method parse_cookie (line 264) | def parse_cookie(self, data_disabled: str, data_enabled: str):
method parse_form (line 273) | def parse_form(self, items: list[str]):
method enabled (line 282) | def enabled(self):
method disabled (line 286) | def disabled(self):
method save (line 289) | def save(self, resp: flask.Response):
method get_disabled (line 296) | def get_disabled(self):
method get_enabled (line 299) | def get_enabled(self):
class EnginesSetting (line 303) | class EnginesSetting(BooleanChoices):
method __init__ (line 306) | def __init__(self, default_value, engines: Iterable[Engine]):
method transform_form_items (line 315) | def transform_form_items(self, items):
method transform_values (line 318) | def transform_values(self, values):
class PluginsSetting (line 328) | class PluginsSetting(BooleanChoices):
method __init__ (line 331) | def __init__(self, default_value, plugins: Iterable[searx.plugins.Plug...
method transform_form_items (line 334) | def transform_form_items(self, items):
class ClientPref (line 338) | class ClientPref:
method __init__ (line 346) | def __init__(self, locale: babel.Locale | None = None):
method locale_tag (line 350) | def locale_tag(self):
method from_http_request (line 359) | def from_http_request(cls, http_request: SXNG_Request):
class Preferences (line 389) | class Preferences:
method __init__ (line 392) | def __init__(
method get_as_url_params (line 499) | def get_as_url_params(self):
method parse_encoded_data (line 520) | def parse_encoded_data(self, input_data: str):
method parse_dict (line 528) | def parse_dict(self, input_data: dict[str, str]):
method parse_form (line 542) | def parse_form(self, input_data: dict[str, str]):
method get_value (line 571) | def get_value(self, user_setting_name: str) -> t.Any:
method save (line 578) | def save(self, resp: flask.Response):
method validate_token (line 590) | def validate_token(self, engine):
function is_locked (line 602) | def is_locked(setting_name: str):
FILE: searx/query.py
class QueryPartParser (line 15) | class QueryPartParser(ABC):
method check (line 21) | def check(raw_value):
method __init__ (line 24) | def __init__(self, raw_text_query, enable_autocomplete):
method __call__ (line 29) | def __call__(self, raw_value):
method _add_autocomplete (line 38) | def _add_autocomplete(self, value):
class TimeoutParser (line 43) | class TimeoutParser(QueryPartParser):
method check (line 45) | def check(raw_value):
method __call__ (line 48) | def __call__(self, raw_value):
method _parse (line 55) | def _parse(self, value):
method _autocomplete (line 67) | def _autocomplete(self):
class LanguageParser (line 72) | class LanguageParser(QueryPartParser):
method check (line 74) | def check(raw_value):
method __call__ (line 77) | def __call__(self, raw_value):
method _parse (line 84) | def _parse(self, value):
method _autocomplete (line 118) | def _autocomplete(self, value):
class ExternalBangParser (line 151) | class ExternalBangParser(QueryPartParser):
method check (line 153) | def check(raw_value):
method __call__ (line 156) | def __call__(self, raw_value):
method _parse (line 163) | def _parse(self, value):
method _autocomplete (line 171) | def _autocomplete(self, bang_ac_list):
class BangParser (line 178) | class BangParser(QueryPartParser):
method check (line 180) | def check(raw_value):
method __call__ (line 184) | def __call__(self, raw_value):
method _parse (line 193) | def _parse(self, value):
method _autocomplete (line 216) | def _autocomplete(self, first_char, value):
class FeelingLuckyParser (line 240) | class FeelingLuckyParser(QueryPartParser):
method check (line 242) | def check(raw_value):
method __call__ (line 245) | def __call__(self, raw_value):
class RawTextQuery (line 250) | class RawTextQuery:
method __init__ (line 261) | def __init__(self, query: str, disabled_engines: list):
method _parse_query (line 280) | def _parse_query(self):
method get_autocomplete_full_query (line 311) | def get_autocomplete_full_query(self, text):
method changeQuery (line 316) | def changeQuery(self, query):
method getQuery (line 323) | def getQuery(self):
method getFullQuery (line 326) | def getFullQuery(self):
method __str__ (line 332) | def __str__(self):
method __repr__ (line 335) | def __repr__(self):
FILE: searx/result_types/__init__.py
class ResultList (line 40) | class ResultList(list[Result | LegacyResult], abc.ABC):
class types (line 44) | class types: # pylint: disable=invalid-name
method __init__ (line 61) | def __init__(self):
method add (line 65) | def add(self, result: Result | LegacyResult):
class EngineResults (line 70) | class EngineResults(ResultList):
FILE: searx/result_types/_base.py
function _normalize_url_fields (line 38) | def _normalize_url_fields(result: "Result | LegacyResult"):
function _normalize_text_fields (line 85) | def _normalize_text_fields(result: "MainResult | LegacyResult"):
function _filter_urls (line 111) | def _filter_urls(
function _normalize_date_fields (line 219) | def _normalize_date_fields(result: "MainResult | LegacyResult"):
class Result (line 228) | class Result(msgspec.Struct, kw_only=True):
method normalize_result_fields (line 248) | def normalize_result_fields(self):
method __post_init__ (line 258) | def __post_init__(self):
method filter_urls (line 261) | def filter_urls(self, filter_func: "Callable[[Result | LegacyResult, s...
method __hash__ (line 288) | def __hash__(self) -> int:
method __eq__ (line 301) | def __eq__(self, other: object):
method __setitem__ (line 310) | def __setitem__(self, field_name: str, value: t.Any):
method __getitem__ (line 314) | def __getitem__(self, field_name: str) -> t.Any:
method __iter__ (line 320) | def __iter__(self):
method as_dict (line 324) | def as_dict(self):
method defaults_from (line 327) | def defaults_from(self, other: "Result"):
class MainResult (line 339) | class MainResult(Result): # pylint: disable=missing-class-docstring
method __hash__ (line 405) | def __hash__(self) -> int:
method normalize_result_fields (line 420) | def normalize_result_fields(self):
class LegacyResult (line 428) | class LegacyResult(dict[str, t.Any]):
method as_dict (line 467) | def as_dict(self):
method __init__ (line 470) | def __init__(self, *args: t.Any, **kwargs: t.Any):
method __getattr__ (line 513) | def __getattr__(self, name: str, default: t.Any = UNSET) -> t.Any:
method __setattr__ (line 518) | def __setattr__(self, name: str, val: t.Any):
method __hash__ (line 521) | def __hash__(self) -> int: # pyright: ignore[reportIncompatibleVariab...
method __eq__ (line 549) | def __eq__(self, other: object):
method __repr__ (line 553) | def __repr__(self) -> str:
method normalize_result_fields (line 557) | def normalize_result_fields(self):
method defaults_from (line 564) | def defaults_from(self, other: "LegacyResult"):
method filter_urls (line 572) | def filter_urls(self, filter_func: "Callable[[Result | LegacyResult, s...
FILE: searx/result_types/answer.py
class BaseAnswer (line 41) | class BaseAnswer(Result, kw_only=True):
class AnswerSet (line 46) | class AnswerSet:
method __init__ (line 49) | def __init__(self):
method __len__ (line 52) | def __len__(self):
method __bool__ (line 55) | def __bool__(self):
method add (line 58) | def add(self, answer: BaseAnswer) -> None:
method __iter__ (line 65) | def __iter__(self):
method __contains__ (line 70) | def __contains__(self, answer: BaseAnswer) -> bool:
class Answer (line 78) | class Answer(BaseAnswer, kw_only=True):
method __hash__ (line 88) | def __hash__(self):
class Translations (line 95) | class Translations(BaseAnswer, kw_only=True):
method __post_init__ (line 124) | def __post_init__(self):
class Item (line 128) | class Item(msgspec.Struct, kw_only=True):
class WeatherAnswer (line 153) | class WeatherAnswer(BaseAnswer, kw_only=True):
class Item (line 169) | class Item(msgspec.Struct, kw_only=True):
method __post_init__ (line 221) | def __post_init__(self):
method url (line 230) | def url(self) -> str | None:
FILE: searx/result_types/code.py
function is_valid_language (line 33) | def is_valid_language(code_language: str) -> bool:
class Code (line 44) | class Code(MainResult, kw_only=True):
method __post_init__ (line 92) | def __post_init__(self):
method __hash__ (line 101) | def __hash__(self):
method get_lexer (line 108) | def get_lexer(self):
method HTML (line 124) | def HTML(self, **options) -> str: # pyright: ignore[reportUnknownPara...
FILE: searx/result_types/file.py
class File (line 26) | class File(MainResult, kw_only=True):
method __post_init__ (line 72) | def __post_init__(self):
FILE: searx/result_types/keyvalue.py
class KeyValue (line 25) | class KeyValue(MainResult, kw_only=True):
method __hash__ (line 43) | def __hash__(self) -> int:
FILE: searx/result_types/paper.py
class Paper (line 33) | class Paper(MainResult, kw_only=True):
method __post_init__ (line 91) | def __post_init__(self):
FILE: searx/results.py
function calculate_score (line 17) | def calculate_score(
class Timing (line 41) | class Timing(t.NamedTuple):
class UnresponsiveEngine (line 47) | class UnresponsiveEngine(t.NamedTuple):
class ResultContainer (line 53) | class ResultContainer:
method __init__ (line 65) | def __init__(self):
method extend (line 83) | def extend(
method _merge_infobox (line 160) | def _merge_infobox(self, new_infobox: LegacyResult):
method _merge_main_result (line 173) | def _merge_main_result(self, result: MainResult | LegacyResult, positi...
method close (line 189) | def close(self):
method get_ordered_results (line 197) | def get_ordered_results(self) -> list[MainResult | LegacyResult]:
method number_of_results (line 256) | def number_of_results(self) -> int:
method add_unresponsive_engine (line 274) | def add_unresponsive_engine(self, engine_name: str, error_type: str, s...
method add_timing (line 282) | def add_timing(self, engine_name: str, engine_time: float, page_load_t...
method get_timings (line 289) | def get_timings(self) -> list[Timing]:
function merge_two_infoboxes (line 297) | def merge_two_infoboxes(origin: LegacyResult, other: LegacyResult):
function merge_two_main_results (line 357) | def merge_two_main_results(origin: MainResult | LegacyResult, other: Mai...
FILE: searx/search/__init__.py
function initialize (line 33) | def initialize(
class Search (line 47) | class Search:
method __init__ (line 50) | def __init__(self, search_query: "SearchQuery"):
method search_external_bang (line 59) | def search_external_bang(self) -> bool:
method search_answerers (line 71) | def search_answerers(self):
method _get_requests (line 78) | def _get_requests(self) -> tuple[list[tuple[str, str, RequestParams]],...
method search_multiple_requests (line 136) | def search_multiple_requests(self, requests: list[tuple[str, str, Requ...
method search_standard (line 160) | def search_standard(self):
method search (line 174) | def search(self) -> ResultContainer:
class SearchWithPlugins (line 182) | class SearchWithPlugins(Search):
method __init__ (line 185) | def __init__(self, search_query: "SearchQuery", request: "SXNG_Request...
method _on_result (line 198) | def _on_result(self, result):
method search (line 201) | def search(self) -> ResultContainer:
FILE: searx/search/models.py
class EngineRef (line 8) | class EngineRef:
method __init__ (line 13) | def __init__(self, name: str, category: str):
method __repr__ (line 17) | def __repr__(self):
method __eq__ (line 20) | def __eq__(self, other):
method __hash__ (line 23) | def __hash__(self):
class SearchQuery (line 28) | class SearchQuery:
method __init__ (line 31) | def __init__(
method categories (line 63) | def categories(self):
method __repr__ (line 66) | def __repr__(self):
method __eq__ (line 79) | def __eq__(self, other):
method __hash__ (line 92) | def __hash__(self):
method __copy__ (line 107) | def __copy__(self):
FILE: searx/search/processors/__init__.py
class ProcessorMap (line 35) | class ProcessorMap(dict[str, EngineProcessor]):
method init (line 47) | def init(self, engine_list: list[dict[str, t.Any]]):
method register_processor (line 71) | def register_processor(self, eng_proc: EngineProcessor, eng_proc_ok: b...
FILE: searx/search/processors/abstract.py
class RequestParams (line 31) | class RequestParams(t.TypedDict):
class SuspendedStatus (line 77) | class SuspendedStatus:
method __init__ (line 80) | def __init__(self):
method is_suspended (line 87) | def is_suspended(self):
method suspend (line 90) | def suspend(self, suspended_time: int | None, suspend_reason: str):
method resume (line 103) | def resume(self):
class EngineProcessor (line 111) | class EngineProcessor(ABC):
method __init__ (line 116) | def __init__(self, engine: "Engine|types.ModuleType"):
method initialize (line 123) | def initialize(self, callback: t.Callable[["EngineProcessor", bool], b...
method init_engine (line 151) | def init_engine(self) -> bool:
method handle_exception (line 165) | def handle_exception(
method _extend_container_basic (line 193) | def _extend_container_basic(
method extend_container (line 210) | def extend_container(
method extend_container_if_suspended (line 225) | def extend_container_if_suspended(self, result_container: "ResultConta...
method get_params (line 233) | def get_params(self, search_query: "SearchQuery", engine_category: str...
method search (line 282) | def search(
method get_tests (line 292) | def get_tests(self):
method get_default_tests (line 296) | def get_default_tests(self):
FILE: searx/search/processors/offline.py
class OfflineProcessor (line 11) | class OfflineProcessor(EngineProcessor):
method search (line 16) | def search(
FILE: searx/search/processors/online.py
class HTTPParams (line 29) | class HTTPParams(t.TypedDict):
class OnlineParams (line 90) | class OnlineParams(HTTPParams, RequestParams):
function default_request_params (line 94) | def default_request_params() -> HTTPParams:
class OnlineProcessor (line 113) | class OnlineProcessor(EngineProcessor):
method init_engine (line 118) | def init_engine(self) -> bool:
method init_network_in_thread (line 124) | def init_network_in_thread(self, start_time: float, timeout_limit: flo...
method get_params (line 132) | def get_params(self, search_query: "SearchQuery", engine_category: str...
method _send_http_request (line 164) | def _send_http_request(self, params: OnlineParams):
method _search_basic (line 223) | def _search_basic(self, query: str, params: OnlineParams) -> "EngineRe...
method search (line 239) | def search( # pyright: ignore[reportIncompatibleMethodOverride]
FILE: searx/search/processors/online_currency.py
class CurrenciesParams (line 24) | class CurrenciesParams(t.TypedDict):
class OnlineCurrenciesParams (line 46) | class OnlineCurrenciesParams(CurrenciesParams, OnlineParams): # pylint:...
class OnlineCurrencyProcessor (line 50) | class OnlineCurrencyProcessor(OnlineProcessor):
method get_params (line 55) | def get_params(self, search_query: "SearchQuery", engine_category: str...
function _normalize_name (line 112) | def _normalize_name(name: str):
FILE: searx/search/processors/online_dictionary.py
class DictParams (line 20) | class DictParams(t.TypedDict):
class OnlineDictParams (line 33) | class OnlineDictParams(DictParams, OnlineParams): # pylint: disable=dup...
class OnlineDictionaryProcessor (line 37) | class OnlineDictionaryProcessor(OnlineProcessor):
method get_params (line 42) | def get_params(self, search_query: "SearchQuery", engine_category: str...
function _get_lang_descr (line 70) | def _get_lang_descr(lang: str) -> FromToType | None:
FILE: searx/search/processors/online_url_search.py
class UrlParams (line 22) | class UrlParams(t.TypedDict):
class OnlineUrlSearchParams (line 28) | class OnlineUrlSearchParams(UrlParams, OnlineParams): # pylint: disable...
class OnlineUrlSearchProcessor (line 32) | class OnlineUrlSearchProcessor(OnlineProcessor):
method get_params (line 37) | def get_params(self, search_query: "SearchQuery", engine_category: str...
FILE: searx/settings_defaults.py
class SettingsValue (line 63) | class SettingsValue:
method __init__ (line 66) | def __init__(
method type_definition_repr (line 79) | def type_definition_repr(self):
method check_type_definition (line 83) | def check_type_definition(self, value: t.Any) -> None:
method __call__ (line 90) | def __call__(self, value: t.Any) -> t.Any:
class SettingSublistValue (line 103) | class SettingSublistValue(SettingsValue):
method check_type_definition (line 107) | def check_type_definition(self, value: list[t.Any]) -> None:
class SettingsDirectoryValue (line 115) | class SettingsDirectoryValue(SettingsValue):
method check_type_definition (line 119) | def check_type_definition(self, value: t.Any) -> t.Any:
method __call__ (line 125) | def __call__(self, value: t.Any) -> t.Any:
class SettingsBytesValue (line 131) | class SettingsBytesValue(SettingsValue):
method __call__ (line 135) | def __call__(self, value: t.Any) -> t.Any:
function apply_schema (line 141) | def apply_schema(settings: dict[str, t.Any], schema: dict[str, t.Any], p...
FILE: searx/settings_loader.py
function load_yaml (line 40) | def load_yaml(file_name: str | Path) -> SettingsType:
function get_yaml_cfg (line 51) | def get_yaml_cfg(file_name: str | Path) -> SettingsType:
function get_user_cfg_folder (line 66) | def get_user_cfg_folder() -> Path | None:
function update_dict (line 118) | def update_dict(default_dict: MutableMapping[str, t.Any], user_dict: Mut...
function update_settings (line 127) | def update_settings(default_settings: MutableMapping[str, t.Any], user_s...
function is_use_default_settings (line 182) | def is_use_default_settings(user_settings: SettingsType) -> bool:
function load_settings (line 194) | def load_settings(load_user_settings: bool = True) -> tuple[SettingsType...
FILE: searx/sqlitedb.py
class DBSession (line 39) | class DBSession:
method get_connect (line 43) | def get_connect(cls, app: "SQLiteAppl") -> sqlite3.Connection:
method __init__ (line 56) | def __init__(self, app: "SQLiteAppl"):
method conn (line 67) | def conn(self) -> sqlite3.Connection:
method __del__ (line 77) | def __del__(self):
class SQLiteAppl (line 91) | class SQLiteAppl(abc.ABC):
method __init__ (line 193) | def __init__(self, db_url: str):
method _compatibility (line 209) | def _compatibility(self):
method _connect (line 229) | def _connect(self) -> sqlite3.Connection:
method connect (line 235) | def connect(self) -> sqlite3.Connection:
method register_functions (line 256) | def register_functions(self, conn: sqlite3.Connection):
method DB (line 281) | def DB(self) -> sqlite3.Connection:
method init (line 319) | def init(self, conn: sqlite3.Connection) -> bool:
method create_schema (line 347) | def create_schema(self, conn: sqlite3.Connection):
class SQLiteProperties (line 358) | class SQLiteProperties(SQLiteAppl):
method __init__ (line 398) | def __init__(self, db_url: str): # pyright: ignore[reportMissingSuper...
method init (line 404) | def init(self, conn: sqlite3.Connection) -> bool:
method __call__ (line 416) | def __call__(self, name: str, default: t.Any = None) -> t.Any:
method set (line 425) | def set(self, name: str, value: str | int):
method delete (line 432) | def delete(self, name: str) -> int:
method row (line 438) | def row(self, name: str, default: t.Any = None):
method m_time (line 450) | def m_time(self, name: str, default: int = 0) -> int:
method create_schema (line 458) | def create_schema(self, conn: sqlite3.Connection):
method __str__ (line 462) | def __str__(self) -> str:
FILE: searx/utils.py
class _NotSetClass (line 60) | class _NotSetClass: # pylint: disable=too-few-public-methods
function searxng_useragent (line 68) | def searxng_useragent() -> str:
function gen_useragent (line 73) | def gen_useragent(os_string: str | None = None) -> str:
function gen_gsa_useragent (line 84) | def gen_gsa_useragent() -> str:
class HTMLTextExtractor (line 92) | class HTMLTextExtractor(HTMLParser):
method __init__ (line 95) | def __init__(self):
method handle_starttag (line 100) | def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]...
method handle_endtag (line 105) | def handle_endtag(self, tag: str) -> None:
method is_valid_tag (line 115) | def is_valid_tag(self):
method handle_data (line 118) | def handle_data(self, data: str) -> None:
method handle_charref (line 123) | def handle_charref(self, name: str) -> None:
method handle_entityref (line 132) | def handle_entityref(self, name: str) -> None:
method get_text (line 139) | def get_text(self):
method error (line 142) | def error(self, message: str) -> None:
function html_to_text (line 148) | def html_to_text(html_str: str) -> str:
function markdown_to_text (line 189) | def markdown_to_text(markdown_str: str) -> str:
function extract_text (line 212) | def extract_text(
function normalize_url (line 256) | def normalize_url(url: str, base_url: str) -> str:
function extract_url (line 306) | def extract_url(xpath_results: list[ElementType] | ElementType | str | N...
function dict_subset (line 343) | def dict_subset(dictionary: MutableMapping[t.Any, t.Any], properties: se...
function humanize_bytes (line 355) | def humanize_bytes(size: int | float, precision: int = 2):
function humanize_number (line 367) | def humanize_number(size: int | float, precision: int = 0):
function convert_str_to_int (line 379) | def convert_str_to_int(number_str: str) -> int:
function extr (line 386) | def extr(txt: str, begin: str, end: str, default: str = "") -> str:
function int_or_zero (line 415) | def int_or_zero(num: list[str] | str) -> int:
function load_module (line 427) | def load_module(filename: str, module_dir: str) -> types.ModuleType:
function to_string (line 441) | def to_string(obj: t.Any) -> str:
function ecma_unescape (line 450) | def ecma_unescape(string: str) -> str:
function remove_pua_from_str (line 471) | def remove_pua_from_str(string: str):
function get_string_replaces_function (line 486) | def get_string_replaces_function(replaces: dict[str, str]) -> Callable[[...
function get_engine_from_settings (line 496) | def get_engine_from_settings(name: str) -> dict[str, dict[str, str]]:
function get_xpath (line 511) | def get_xpath(xpath_spec: XPathSpecType) -> XPath:
function eval_xpath (line 537) | def eval_xpath(element: ElementType, xpath_spec: XPathSpecType) -> t.Any:
function eval_xpath_list (line 565) | def eval_xpath_list(element: ElementType, xpath_spec: XPathSpecType, min...
function eval_xpath_getindex (line 578) | def eval_xpath_getindex(
function get_embeded_stream_url (line 602) | def get_embeded_stream_url(url: str):
function _j2p_process_escape (line 664) | def _j2p_process_escape(match: re.Match[str]) -> str:
function _j2p_decimal (line 674) | def _j2p_decimal(match: re.Match[str]) -> str:
function _j2p_decimal2 (line 684) | def _j2p_decimal2(match: re.Match[str]) -> str:
function js_obj_str_to_python (line 688) | def js_obj_str_to_python(js_obj_str: str) -> t.Any:
function js_obj_str_to_json_str (line 705) | def js_obj_str_to_json_str(js_obj_str: str) -> str:
function parse_duration_string (line 792) | def parse_duration_string(duration_str: str) -> timedelta | None:
FILE: searx/valkeydb.py
function client (line 33) | def client() -> valkey.Valkey | None:
function initialize (line 38) | def initialize():
FILE: searx/valkeylib.py
function lua_script_storage (line 21) | def lua_script_storage(client, script):
function purge_by_prefix (line 52) | def purge_by_prefix(client, prefix: str = "SearXNG_"):
function secret_hash (line 75) | def secret_hash(name: str):
function incr_counter (line 112) | def incr_counter(client, name: str, limit: int = 0, expire: int = 0):
function drop_counter (line 159) | def drop_counter(client, name):
function incr_sliding_window (line 182) | def incr_sliding_window(client, name: str, duration: int):
FILE: searx/version.py
function subprocess_run (line 29) | def subprocess_run(args: str | list[str] | tuple[str], **kwargs) -> str:...
function get_git_url_and_branch (line 47) | def get_git_url_and_branch():
function get_git_version (line 70) | def get_git_version() -> tuple[str, str, str]:
function get_information (line 82) | def get_information() -> tuple[str, str, str, str, str, str, str]:
function get_git_version_upstream (line 111) | def get_git_version_upstream():
function get_git_fork_commit (line 121) | def get_git_fork_commit():
FILE: searx/weather.py
function get_WEATHER_DATA_CACHE (line 47) | def get_WEATHER_DATA_CACHE():
function _get_sxng_locale_tag (line 62) | def _get_sxng_locale_tag() -> str:
function symbol_url (line 97) | def symbol_url(condition: "WeatherConditionType") -> str | None:
class GeoLocation (line 127) | class GeoLocation(msgspec.Struct, kw_only=True):
method zoneinfo (line 145) | def zoneinfo(self) -> zoneinfo.ZoneInfo:
method __str__ (line 148) | def __str__(self):
method locale (line 151) | def locale(self) -> babel.Locale:
method by_query (line 174) | def by_query(cls, search_term: str) -> "GeoLocation":
method _query_open_meteo (line 193) | def _query_open_meteo(cls, search_term: str) -> dict[str, str]:
class DateTime (line 209) | class DateTime(msgspec.Struct):
method __str__ (line 225) | def __str__(self):
method l10n (line 228) | def l10n(
method l10n_date (line 242) | def l10n_date(
class Temperature (line 262) | class Temperature(msgspec.Struct, kw_only=True):
method __post_init__ (line 272) | def __post_init__(self):
method __str__ (line 276) | def __str__(self):
method value (line 279) | def value(self, unit: TemperatureUnit) -> float:
method l10n (line 285) | def l10n(
class Pressure (line 330) | class Pressure(msgspec.Struct, kw_only=True):
method __post_init__ (line 340) | def __post_init__(self):
method __str__ (line 344) | def __str__(self):
method value (line 347) | def value(self, unit: PressureUnit) -> float:
method l10n (line 353) | def l10n(
class WindSpeed (line 376) | class WindSpeed(msgspec.Struct, kw_only=True):
method __post_init__ (line 393) | def __post_init__(self):
method __str__ (line 397) | def __str__(self):
method value (line 400) | def value(self, unit: WindSpeedUnit) -> float:
method l10n (line 406) | def l10n(
class RelativeHumidity (line 429) | class RelativeHumidity(msgspec.Struct):
method __post_init__ (line 438) | def __post_init__(self):
method __str__ (line 442) | def __str__(self):
method value (line 445) | def value(self) -> float:
method l10n (line 448) | def l10n(
class Compass (line 474) | class Compass(msgspec.Struct):
method __post_init__ (line 490) | def __post_init__(self):
method __str__ (line 499) | def __str__(self):
method value (line 502) | def value(self, unit: CompassUnit):
method point (line 510) | def point(cls, azimuth: float | int) -> CompassPoint:
method l10n (line 519) | def l10n(
FILE: searx/webadapter.py
function deduplicate_engineref_list (line 16) | def deduplicate_engineref_list(engineref_list: List[EngineRef]) -> List[...
function validate_engineref_list (line 21) | def validate_engineref_list(
function parse_pageno (line 48) | def parse_pageno(form: Dict[str, str]) -> int:
function parse_lang (line 55) | def parse_lang(preferences: Preferences, form: Dict[str, str], raw_text_...
function parse_safesearch (line 75) | def parse_safesearch(preferences: Preferences, form: Dict[str, str]) -> ...
function parse_time_range (line 95) | def parse_time_range(form: Dict[str, str]) -> Optional[str]:
function parse_timeout (line 104) | def parse_timeout(form: Dict[str, str], raw_text_query: RawTextQuery) ->...
function parse_category_form (line 117) | def parse_category_form(query_categories: List[str], name: str, value: s...
function get_selected_categories (line 135) | def get_selected_categories(preferences: Preferences, form: Optional[Dic...
function get_engineref_from_category_list (line 158) | def get_engineref_from_category_list( # pylint: disable=invalid-name
function parse_generic (line 172) | def parse_generic(preferences: Preferences, form: Dict[str, str], disabl...
function parse_engine_data (line 212) | def parse_engine_data(form):
function get_search_query_from_webapp (line 221) | def get_search_query_from_webapp(
FILE: searx/webapp.py
function get_locale (line 155) | def get_locale():
function _get_browser_language (line 164) | def _get_browser_language(req, lang_list):
function _get_locale_rfc5646 (line 170) | def _get_locale_rfc5646(locale):
function code_highlighter (line 182) | def code_highlighter(codelines, language=None, hl_lines=None, strip_whit...
function get_result_template (line 247) | def get_result_template(theme_name: str, template_name: str):
function custom_url_for (line 257) | def custom_url_for(endpoint: str, **values):
function image_proxify (line 298) | def image_proxify(url: str):
function get_translations (line 324) | def get_translations():
function get_enabled_categories (line 335) | def get_enabled_categories(category_names: typing.Iterable[str]):
function get_pretty_url (line 346) | def get_pretty_url(parsed_url: urllib.parse.ParseResult):
function get_client_settings (line 367) | def get_client_settings():
function render (line 389) | def render(template_name: str, **kwargs):
function pre_request (line 461) | def pre_request():
function add_default_headers (line 523) | def add_default_headers(response: flask.Response):
function post_request (line 533) | def post_request(response: flask.Response):
function index_error (line 554) | def index_error(output_format: str, error_message: str):
function index (line 584) | def index():
function health (line 602) | def health():
function client_token (line 607) | def client_token(token=None):
function rss_xsl (line 613) | def rss_xsl():
function search (line 621) | def search():
function about (line 790) | def about():
function info (line 797) | def info(pagename, locale):
function autocompleter (line 813) | def autocompleter():
function preferences (line 862) | def preferences():
function image_proxy (line 1004) | def image_proxy():
function engine_descriptions (line 1076) | def engine_descriptions():
function stats (line 1102) | def stats():
function stats_errors (line 1163) | def stats_errors():
function stats_open_metrics (line 1170) | def stats_open_metrics():
function robots (line 1189) | def robots():
function opensearch (line 1203) | def opensearch():
function manifest (line 1220) | def manifest():
function manifest_logo (line 1233) | def manifest_logo(resolution=0):
function favicon (line 1243) | def favicon():
function clear_cookies (line 1253) | def clear_cookies():
function config (line 1261) | def config():
function page_not_found (line 1323) | def page_not_found(_e):
function run (line 1327) | def run():
function init (line 1364) | def init():
function static_headers (line 1387) | def static_headers(headers: Headers, _path: str, _url: str) -> None:
FILE: searx/webutils.py
function get_translated_errors (line 70) | def get_translated_errors(unresponsive_engines: "Iterable[UnresponsiveEn...
class CSVWriter (line 85) | class CSVWriter:
method __init__ (line 89) | def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
method writerow (line 96) | def writerow(self, row):
method writerows (line 108) | def writerows(self, rows):
function write_csv_response (line 113) | def write_csv_response(csv: CSVWriter, rc: "ResultContainer") -> None: ...
class JSONEncoder (line 149) | class JSONEncoder(json.JSONEncoder): # pylint: disable=missing-class-do...
method default (line 150) | def default(self, o):
function get_json_response (line 162) | def get_json_response(sq: "SearchQuery", rc: "ResultContainer") -> str:
function get_themes (line 178) | def get_themes(templates_path):
function get_static_file_list (line 183) | def get_static_file_list() -> list[str]:
function get_result_templates (line 201) | def get_result_templates(templates_path):
function new_hmac (line 212) | def new_hmac(secret_key, url):
function is_hmac_of (line 216) | def is_hmac_of(secret_key, value, hmac_to_check):
function prettify_url (line 221) | def prettify_url(url, max_length=74):
function contains_cjko (line 228) | def contains_cjko(s: str) -> bool:
function regex_highlight_cjk (line 250) | def regex_highlight_cjk(word: str) -> str:
function highlight_content (line 270) | def highlight_content(content, query):
function searxng_l10n_timespan (line 291) | def searxng_l10n_timespan(dt: datetime) -> str: # pylint: disable=inval...
function group_engines_in_tab (line 316) | def group_engines_in_tab(engines: "Iterable[Engine]") -> List[Tuple[str,...
FILE: searx/wikidata_units.py
class Beaufort (line 17) | class Beaufort:
method from_si (line 40) | def from_si(cls, value) -> float:
method to_si (line 50) | def to_si(cls, value) -> float:
function convert_from_si (line 119) | def convert_from_si(si_name: str, symbol: str, value: float | int) -> fl...
function convert_to_si (line 128) | def convert_to_si(si_name: str, symbol: str, value: float | int) -> float:
function units_by_si_name (line 137) | def units_by_si_name(si_name):
function symbol_to_si (line 165) | def symbol_to_si():
function fetch_units (line 269) | def fetch_units():
FILE: searxng_extra/update/update_ahmia_blacklist.py
function fetch_ahmia_blacklist (line 21) | def fetch_ahmia_blacklist():
FILE: searxng_extra/update/update_currencies.py
function remove_accents (line 59) | def remove_accents(name):
function remove_extra (line 63) | def remove_extra(name):
function _normalize_name (line 70) | def _normalize_name(name):
function add_currency_name (line 76) | def add_currency_name(db, name, iso4217, normalize_name=True):
function add_currency_label (line 87) | def add_currency_label(db, label, iso4217, language):
function wikidata_request_result_iterator (line 92) | def wikidata_request_result_iterator(request):
function fetch_db (line 98) | def fetch_db():
function main (line 131) | def main():
FILE: searxng_extra/update/update_engine_descriptions.py
function normalize_description (line 88) | def normalize_description(description):
function update_description (line 95) | def update_description(engine_name, lang, description, source, replace=T...
function get_wikipedia_summary (line 112) | def get_wikipedia_summary(wikipedia_url, searxng_locale):
function get_website_description (line 139) | def get_website_description(url, lang1, lang2=None):
function initialize (line 178) | def initialize():
function fetch_wikidata_descriptions (line 208) | def fetch_wikidata_descriptions():
function fetch_wikipedia_descriptions (line 230) | def fetch_wikipedia_descriptions():
function normalize_url (line 254) | def normalize_url(url):
function fetch_website_description (line 261) | def fetch_website_description(engine_name, website):
function fetch_website_descriptions (line 314) | def fetch_website_descriptions():
function get_engine_descriptions_filename (line 326) | def get_engine_descriptions_filename():
function get_output (line 330) | def get_output():
function main (line 359) | def main():
FILE: searxng_extra/update/update_engine_traits.py
function cli (line 85) | def cli(engines: t.Annotated[list[str] | None, typer.Argument()] = None):
function fetch_traits_map (line 119) | def fetch_traits_map() -> EngineTraitsMap:
function filter_locales (line 131) | def filter_locales(traits_map: EngineTraitsMap) -> set[str]:
function write_sxng_locales_file (line 165) | def write_sxng_locales_file(sxng_tag_list: set[str]):
class UnicodeEscape (line 196) | class UnicodeEscape(str):
method __repr__ (line 199) | def __repr__(self):
function get_unicode_flag (line 203) | def get_unicode_flag(locale: babel.Locale):
FILE: searxng_extra/update/update_external_bangs.py
function main (line 25) | def main():
function merge_when_no_leaf (line 39) | def merge_when_no_leaf(node):
function optimize_leaf (line 85) | def optimize_leaf(parent, parent_key, node):
function parse_ddg_bangs (line 96) | def parse_ddg_bangs(ddg_bangs):
FILE: searxng_extra/update/update_firefox_version.py
function fetch_firefox_versions (line 40) | def fetch_firefox_versions():
function fetch_firefox_last_versions (line 60) | def fetch_firefox_last_versions():
FILE: searxng_extra/update/update_gsa_useragents.py
function fetch_gsa_useragents (line 23) | def fetch_gsa_useragents() -> list[str]:
FILE: searxng_extra/update/update_locales.py
function main (line 30) | def main():
function get_locale_descr (line 67) | def get_locale_descr(locale: babel.Locale, tr_locale):
function _get_locale_descr (line 92) | def _get_locale_descr(locale: babel.Locale, tr_locale: str) -> tuple[str...
FILE: searxng_extra/update/update_osm_keys_tags.py
function get_preset_keys (line 93) | def get_preset_keys():
function get_keys (line 103) | def get_keys():
function get_tags (line 149) | def get_tags():
function optimize_data_lang (line 165) | def optimize_data_lang(translations):
function optimize_tags (line 190) | def optimize_tags(data):
function optimize_keys (line 197) | def optimize_keys(data):
FILE: searxng_extra/update/update_pygments.py
class Formatter (line 49) | class Formatter(HtmlFormatter): # pylint: disable=missing-class-docstring
method get_style_lines (line 51) | def get_style_lines(self, arg=None):
function generat_css (line 59) | def generat_css(light_style, dark_style) -> str:
FILE: tests/__init__.py
class SearxTestLayer (line 13) | class SearxTestLayer:
method setUp (line 19) | def setUp(cls):
method tearDown (line 23) | def tearDown(cls):
method testSetUp (line 27) | def testSetUp(cls):
method testTearDown (line 31) | def testTearDown(cls):
class SearxTestCase (line 35) | class SearxTestCase(aiounittest.AsyncTestCase):
method setUp (line 43) | def setUp(self):
method setattr4test (line 46) | def setattr4test(self, obj, attr, value):
method init_test_settings (line 57) | def init_test_settings(self):
FILE: tests/robot/__main__.py
class SearxRobotLayer (line 18) | class SearxRobotLayer:
method setUp (line 21) | def setUp(self):
method tearDown (line 40) | def tearDown(self):
function run_robot_tests (line 46) | def run_robot_tests(tests):
function main (line 56) | def main():
FILE: tests/robot/test_webapp.py
function test_index (line 9) | def test_index(browser):
function test_404 (line 15) | def test_404(browser):
function test_about (line 21) | def test_about(browser):
function test_preferences (line 27) | def test_preferences(browser):
function test_preferences_engine_select (line 36) | def test_preferences_engine_select(browser):
function test_preferences_locale (line 57) | def test_preferences_locale(browser):
function test_search (line 73) | def test_search(browser):
FILE: tests/unit/engines/test_command.py
class TestCommandEngine (line 10) | class TestCommandEngine(SearxTestCase):
method test_basic_seq_command_engine (line 12) | def test_basic_seq_command_engine(self):
method test_delimiter_parsing (line 27) | def test_delimiter_parsing(self):
method test_regex_parsing (line 125) | def test_regex_parsing(self):
method test_working_dir_path_query (line 182) | def test_working_dir_path_query(self):
method test_enum_queries (line 202) | def test_enum_queries(self):
FILE: tests/unit/engines/test_json_engine.py
class TestJsonEngine (line 15) | class TestJsonEngine(SearxTestCase): # pylint: disable=missing-class-do...
method setUp (line 112) | def setUp(self):
method test_request (line 115) | def test_request(self):
method test_response (line 148) | def test_response(self):
method test_response_results_json (line 201) | def test_response_results_json(self):
FILE: tests/unit/engines/test_xpath.py
class TestXpathEngine (line 15) | class TestXpathEngine(SearxTestCase):
method setUp (line 31) | def setUp(self):
method test_request (line 35) | def test_request(self):
method test_response (line 57) | def test_response(self):
method test_response_results_xpath (line 96) | def test_response_results_xpath(self):
FILE: tests/unit/network/test_network.py
class TestNetwork (line 11) | class TestNetwork(SearxTestCase):
method test_simple (line 14) | def test_simple(self):
method test_ipaddress_cycle (line 20) | def test_ipaddress_cycle(self):
method test_proxy_cycles (line 48) | def test_proxy_cycles(self):
method test_get_kwargs_clients (line 73) | def test_get_kwargs_clients(self):
method test_get_client (line 91) | async def test_get_client(self):
method test_aclose (line 108) | async def test_aclose(self):
method test_request (line 113) | async def test_request(self):
class TestNetworkRequestRetries (line 123) | class TestNetworkRequestRetries(SearxTestCase):
method setUp (line 127) | def setUp(self):
method get_response_404_then_200 (line 131) | def get_response_404_then_200(cls):
method test_retries_ok (line 143) | async def test_retries_ok(self):
method test_retries_fail_int (line 150) | async def test_retries_fail_int(self):
method test_retries_fail_list (line 157) | async def test_retries_fail_list(self):
method test_retries_fail_bool (line 164) | async def test_retries_fail_bool(self):
method test_retries_exception_then_200 (line 171) | async def test_retries_exception_then_200(self):
method test_retries_exception (line 188) | async def test_retries_exception(self):
class TestNetworkStreamRetries (line 199) | class TestNetworkStreamRetries(SearxTestCase):
method setUp (line 203) | def setUp(self):
method get_response_exception_then_200 (line 207) | def get_response_exception_then_200(cls):
method test_retries_ok (line 219) | async def test_retries_ok(self):
method test_retries_fail (line 226) | async def test_retries_fail(self):
method test_retries_exception (line 233) | async def test_retries_exception(self):
FILE: tests/unit/processors/test_online.py
class TestOnlineProcessor (line 13) | class TestOnlineProcessor(SearxTestCase):
method _get_params (line 15) | def _get_params(self, online_processor, search_query, engine_category):
method test_get_params_default_params (line 21) | def test_get_params_default_params(self):
method test_get_params_useragent (line 33) | def test_get_params_useragent(self):
FILE: tests/unit/test_answerers.py
class AnswererTest (line 15) | class AnswererTest(SearxTestCase):
method setUp (line 17) | def setUp(self):
method test_unicode_input (line 26) | def test_unicode_input(self, answerer_obj: searx.answerers.Answerer):
FILE: tests/unit/test_engine_github_code.py
class GithubCodeTests (line 14) | class GithubCodeTests(SearxTestCase):
method setUp (line 18) | def setUp(self):
method tearDown (line 23) | def tearDown(self):
method test_code_extraction (line 102) | def test_code_extraction(self, code_matches, expected_code, expected_h...
method test_transforms_response (line 107) | def test_transforms_response(self):
FILE: tests/unit/test_engine_tineye.py
class TinEyeTests (line 15) | class TinEyeTests(SearxTestCase):
method setUp (line 19) | def setUp(self):
method tearDown (line 24) | def tearDown(self):
method test_status_code_raises (line 27) | def test_status_code_raises(self):
method test_returns_empty_list (line 34) | def test_returns_empty_list(self, status_code):
method test_logs_format_for_422 (line 43) | def test_logs_format_for_422(self):
method test_logs_signature_for_422 (line 53) | def test_logs_signature_for_422(self):
method test_logs_download_for_422 (line 63) | def test_logs_download_for_422(self):
method test_logs_description_for_400 (line 73) | def test_logs_description_for_400(self):
method test_crawl_date_parses (line 84) | def test_crawl_date_parses(self):
FILE: tests/unit/test_engines_init.py
class TestEnginesInit (line 8) | class TestEnginesInit(SearxTestCase):
method test_initialize_engines_default (line 10) | def test_initialize_engines_default(self):
method test_initialize_engines_exclude_onions (line 21) | def test_initialize_engines_exclude_onions(self):
method test_initialize_engines_include_onions (line 33) | def test_initialize_engines_include_onions(self):
method test_missing_name_field (line 56) | def test_missing_name_field(self):
method test_missing_engine_field (line 66) | def test_missing_engine_field(self):
FILE: tests/unit/test_exceptions.py
class TestExceptions (line 10) | class TestExceptions(SearxTestCase):
method test_default_suspend_time (line 19) | def test_default_suspend_time(self, exception):
method test_custom_suspend_time (line 34) | def test_custom_suspend_time(self, exception):
FILE: tests/unit/test_external_bangs.py
class TestGetNode (line 37) | class TestGetNode(SearxTestCase):
method test_found (line 48) | def test_found(self):
method test_get_partial (line 55) | def test_get_partial(self):
method test_not_found (line 61) | def test_not_found(self):
class TestResolveBangDefinition (line 68) | class TestResolveBangDefinition(SearxTestCase):
method test_https (line 70) | def test_https(self):
method test_http (line 75) | def test_http(self):
class TestGetBangDefinitionAndAutocomplete (line 81) | class TestGetBangDefinitionAndAutocomplete(SearxTestCase):
method test_found (line 83) | def test_found(self):
method test_found_optimized (line 88) | def test_found_optimized(self):
method test_partial (line 93) | def test_partial(self):
method test_partial2 (line 98) | def test_partial2(self):
method test_error (line 103) | def test_error(self):
method test_actual_data (line 108) | def test_actual_data(self):
class TestExternalBangJson (line 114) | class TestExternalBangJson(SearxTestCase):
method test_no_external_bang_query (line 116) | def test_no_external_bang_query(self):
method test_get_bang_url (line 120) | def test_get_bang_url(self):
method test_actual_data (line 124) | def test_actual_data(self):
FILE: tests/unit/test_js_variable_to_python.py
class TestParser (line 21) | class TestParser(SearxTestCase):
method test_parse_object (line 33) | def test_parse_object(self, js, expected_py):
method test_parse_list (line 48) | def test_parse_list(self, js, expected_py):
method test_parse_mixed (line 71) | def test_parse_mixed(self, js, expected_py):
method test_parse_standard_values (line 92) | def test_parse_standard_values(self, js, expected_py):
method test_parse_nan (line 96) | def test_parse_nan(self):
method test_parse_strange_values (line 122) | def test_parse_strange_values(self, js, expected_py):
method test_strange_input (line 135) | def test_strange_input(self, js, expected_py):
method test_integer_numeric_values (line 173) | def test_integer_numeric_values(self, js, expected_py):
method test_float_numeric_values (line 199) | def test_float_numeric_values(self, js, expected_py):
class TestParserExceptions (line 211) | class TestParserExceptions(SearxTestCase):
method test_exceptions (line 219) | def test_exceptions(self, js, expected_exception):
method test_malformed_input (line 228) | def test_malformed_input(self, in_data, expected_exception):
method test_error_messages (line 241) | def test_error_messages(self, js, expected_exception, expected_excepti...
class TestParseJsonObjects (line 257) | class TestParseJsonObjects(SearxTestCase):
method test_parse_json_objects (line 284) | def test_parse_json_objects(self, js, expected_py):
FILE: tests/unit/test_locales.py
class TestLocales (line 12) | class TestLocales(SearxTestCase):
method setUpClass (line 19) | def setUpClass(cls):
method test_locale_languages (line 29) | def test_locale_languages(self, locale: str):
method test_match_region (line 46) | def test_match_region(self, locale: str, expected_locale: str):
method test_match_lang_script_code (line 58) | def test_match_lang_script_code(self, locale: str, expected_locale: str):
method test_locale_de (line 62) | def test_locale_de(self):
method test_locale_es (line 66) | def test_locale_es(self):
method test_locale_optimized_selected (line 90) | def test_locale_optimized_selected(self, locale: str, locale_list: lis...
method test_locale_optimized_territory (line 115) | def test_locale_optimized_territory(self, locale: str, locale_list: li...
FILE: tests/unit/test_plugin_hash.py
class PluginHashTest (line 35) | class PluginHashTest(SearxTestCase):
method setUp (line 37) | def setUp(self):
method test_plugin_store_init (line 47) | def test_plugin_store_init(self):
method test_hash_digest_new (line 51) | def test_hash_digest_new(self, query: str, res: str):
method test_pageno_1_2 (line 59) | def test_pageno_1_2(self):
FILE: tests/unit/test_plugin_self_info.py
class PluginIPSelfInfo (line 20) | class PluginIPSelfInfo(SearxTestCase):
method setUp (line 22) | def setUp(self):
method test_plugin_store_init (line 35) | def test_plugin_store_init(self):
method test_IPv4_X_Forwarded_For (line 38) | def test_IPv4_X_Forwarded_For(self):
method test_IPv6_X_Forwarded_For (line 47) | def test_IPv6_X_Forwarded_For(self):
method test_IPv6_X_Forwarded_For_all_trusted (line 57) | def test_IPv6_X_Forwarded_For_all_trusted(self):
method test_IPv6_X_Real_IP (line 66) | def test_IPv6_X_Real_IP(self):
method test_REMOTE_ADDR_is_invalid (line 75) | def test_REMOTE_ADDR_is_invalid(self):
method test_X_Real_IP_is_invalid (line 88) | def test_X_Real_IP_is_invalid(self):
method test_X_Forwarded_For_is_invalid (line 102) | def test_X_Forwarded_For_is_invalid(self):
method test_user_agent_in_answer (line 124) | def test_user_agent_in_answer(self, query: str):
FILE: tests/unit/test_plugins.py
function get_search_mock (line 21) | def get_search_mock(query, **kwargs):
function do_pre_search (line 35) | def do_pre_search(query, storage, **kwargs) -> bool:
function do_post_search (line 42) | def do_post_search(query, storage, **kwargs) -> Mock:
class PluginMock (line 49) | class PluginMock(searx.plugins.Plugin):
method __init__ (line 51) | def __init__(self, _id: str, name: str, active: bool):
method pre_search (line 58) | def pre_search(self, request, search) -> bool:
method post_search (line 61) | def post_search(self, request, search) -> None:
method on_result (line 64) | def on_result(self, request, search, result) -> bool:
method info (line 67) | def info(self):
class PluginStorage (line 76) | class PluginStorage(SearxTestCase):
method setUp (line 78) | def setUp(self):
method test_init (line 89) | def test_init(self):
method test_hooks (line 93) | def test_hooks(self):
FILE: tests/unit/test_preferences.py
class TestSettings (line 29) | class TestSettings(SearxTestCase):
method test_map_setting_invalid_default_value (line 33) | def test_map_setting_invalid_default_value(self):
method test_map_setting_invalid_choice (line 37) | def test_map_setting_invalid_choice(self):
method test_map_setting_valid_default (line 42) | def test_map_setting_valid_default(self):
method test_map_setting_valid_choice (line 46) | def test_map_setting_valid_choice(self):
method test_enum_setting_invalid_default_value (line 54) | def test_enum_setting_invalid_default_value(self):
method test_enum_setting_invalid_choice (line 58) | def test_enum_setting_invalid_choice(self):
method test_enum_setting_valid_default (line 63) | def test_enum_setting_valid_default(self):
method test_enum_setting_valid_choice (line 67) | def test_enum_setting_valid_choice(self):
method test_multiple_setting_invalid_default_value (line 75) | def test_multiple_setting_invalid_default_value(self):
method test_multiple_setting_invalid_choice (line 79) | def test_multiple_setting_invalid_choice(self):
method test_multiple_setting_valid_default (line 84) | def test_multiple_setting_valid_default(self):
method test_multiple_setting_valid_choice (line 88) | def test_multiple_setting_valid_choice(self):
method test_lang_setting_valid_choice (line 96) | def test_lang_setting_valid_choice(self):
method test_lang_setting_invalid_choice (line 101) | def test_lang_setting_invalid_choice(self):
method test_lang_setting_old_cookie_choice (line 106) | def test_lang_setting_old_cookie_choice(self):
method test_lang_setting_old_cookie_format (line 111) | def test_lang_setting_old_cookie_format(self):
method test_plugins_setting_all_default_enabled (line 118) | def test_plugins_setting_all_default_enabled(self):
method test_plugins_setting_few_default_enabled (line 125) | def test_plugins_setting_few_default_enabled(self):
class TestPreferences (line 134) | class TestPreferences(SearxTestCase):
method setUp (line 136) | def setUp(self):
method test_encode (line 142) | def test_encode(self):
method test_save_key_value_setting (line 175) | def test_save_key_value_setting(self):
method test_false_key_value_setting (line 196) | def test_false_key_value_setting(self):
FILE: tests/unit/test_query.py
class TestQuery (line 9) | class TestQuery(SearxTestCase):
method test_simple_query (line 11) | def test_simple_query(self):
method test_multiple_spaces_query (line 21) | def test_multiple_spaces_query(self):
method test_str_method (line 31) | def test_str_method(self):
method test_repr_method (line 36) | def test_repr_method(self):
method test_change_query (line 42) | def test_change_query(self):
class TestLanguageParser (line 50) | class TestLanguageParser(SearxTestCase):
method test_language_code (line 52) | def test_language_code(self):
method test_language_name (line 64) | def test_language_name(self):
method test_unlisted_language_code (line 75) | def test_unlisted_language_code(self):
method test_auto_language_code (line 86) | def test_auto_language_code(self):
method test_invalid_language_code (line 97) | def test_invalid_language_code(self):
method test_empty_colon_in_query (line 108) | def test_empty_colon_in_query(self):
method test_autocomplete_empty (line 117) | def test_autocomplete_empty(self):
method test_autocomplete (line 130) | def test_autocomplete(self, query: str, autocomplete_list: list):
class TestTimeoutParser (line 135) | class TestTimeoutParser(SearxTestCase):
method test_timeout_limit (line 144) | def test_timeout_limit(self, query_text: str, timeout_limit: float):
method test_timeout_invalid (line 151) | def test_timeout_invalid(self):
method test_timeout_autocomplete (line 162) | def test_timeout_autocomplete(self):
class TestExternalBangParser (line 175) | class TestExternalBangParser(SearxTestCase):
method test_external_bang (line 177) | def test_external_bang(self):
method test_external_bang_not_found (line 185) | def test_external_bang_not_found(self):
method test_external_bang_autocomplete (line 193) | def test_external_bang_autocomplete(self):
class TestBang (line 206) | class TestBang(SearxTestCase):
method test_bang (line 212) | def test_bang(self, bang: str):
method test_specific (line 222) | def test_specific(self, bang: str):
method test_bang_not_found (line 228) | def test_bang_not_found(self):
method test_bang_autocomplete (line 232) | def test_bang_autocomplete(self):
method test_bang_autocomplete_empty (line 240) | def test_bang_autocomplete_empty(self):
FILE: tests/unit/test_results.py
class ResultContainerTestCase (line 10) | class ResultContainerTestCase(SearxTestCase):
method test_empty (line 15) | def test_empty(self):
method test_one_result (line 19) | def test_one_result(self):
method test_one_suggestion (line 32) | def test_one_suggestion(self):
method test_merge_url_result (line 43) | def test_merge_url_result(self):
FILE: tests/unit/test_search.py
class SearchQueryTestCase (line 17) | class SearchQueryTestCase(SearxTestCase):
method test_repr (line 19) | def test_repr(self):
method test_eq (line 25) | def test_eq(self):
method test_copy (line 31) | def test_copy(self):
class SearchTestCase (line 37) | class SearchTestCase(SearxTestCase):
method test_timeout_simple (line 39) | def test_timeout_simple(self):
method test_timeout_query_above_default_nomax (line 49) | def test_timeout_query_above_default_nomax(self):
method test_timeout_query_below_default_nomax (line 59) | def test_timeout_query_below_default_nomax(self):
method test_timeout_query_below_max (line 69) | def test_timeout_query_below_max(self):
method test_timeout_query_above_max (line 79) | def test_timeout_query_above_max(self):
method test_external_bang_valid (line 89) | def test_external_bang_valid(self):
method test_external_bang_none (line 105) | def test_external_bang_none(self):
FILE: tests/unit/test_settings_loader.py
function _settings (line 16) | def _settings(f_name):
class TestLoad (line 20) | class TestLoad(SearxTestCase):
method test_load_zero (line 22) | def test_load_zero(self):
class TestDefaultSettings (line 32) | class TestDefaultSettings(SearxTestCase):
method test_load (line 34) | def test_load(self):
class TestUserSettings (line 47) | class TestUserSettings(SearxTestCase):
method test_is_use_default_settings (line 49) | def test_is_use_default_settings(self):
method test_user_settings_not_found (line 64) | def test_user_settings_not_found(self, path: str):
method test_user_settings (line 69) | def test_user_settings(self):
method test_user_settings_remove (line 76) | def test_user_settings_remove(self):
method test_user_settings_remove2 (line 87) | def test_user_settings_remove2(self):
method test_user_settings_keep_only (line 103) | def test_user_settings_keep_only(self):
method test_custom_settings (line 112) | def test_custom_settings(self):
FILE: tests/unit/test_utils.py
function random_string (line 15) | def random_string(length, choices=string.ascii_letters):
class TestUtils (line 19) | class TestUtils(SearxTestCase):
method test_gen_useragent (line 21) | def test_gen_useragent(self):
method test_searxng_useragent (line 26) | def test_searxng_useragent(self):
method test_extract_text (line 31) | def test_extract_text(self):
method test_extract_text_allow_none (line 53) | def test_extract_text_allow_none(self):
method test_extract_text_error_none (line 56) | def test_extract_text_error_none(self):
method test_extract_text_error_empty (line 60) | def test_extract_text_error_empty(self):
method test_extract_url (line 64) | def test_extract_url(self):
method test_ecma_unscape (line 78) | def test_ecma_unscape(self):
method test_html_to_text (line 92) | def test_html_to_text(self, html_str: str, text_str: str):
method test_html_to_text_with_a_style_span (line 95) | def test_html_to_text_with_a_style_span(self):
class TestXPathUtils (line 118) | class TestXPathUtils(SearxTestCase): # pylint: disable=missing-class-do...
method test_get_xpath_cache (line 125) | def test_get_xpath_cache(self):
method test_get_xpath_type (line 133) | def test_get_xpath_type(self):
method test_get_xpath_invalid (line 139) | def test_get_xpath_invalid(self):
method test_eval_xpath_unregistered_function (line 147) | def test_eval_xpath_unregistered_function(self):
method test_eval_xpath (line 157) | def test_eval_xpath(self):
method test_eval_xpath_list (line 164) | def test_eval_xpath_list(self):
method test_eval_xpath_getindex (line 176) | def test_eval_xpath_getindex(self):
FILE: tests/unit/test_webadapter.py
class ValidateQueryCase (line 17) | class ValidateQueryCase(SearxTestCase):
method test_without_token (line 19) | def test_without_token(self):
method test_with_incorrect_token (line 26) | def test_with_incorrect_token(self):
method test_with_correct_token (line 34) | def test_with_correct_token(self):
FILE: tests/unit/test_webapp.py
class ViewsTestCase (line 18) | class ViewsTestCase(SearxTestCase): # pylint: disable=too-many-public-m...
method setUp (line 20) | def setUp(self):
method test_index_empty (line 82) | def test_index_empty(self):
method test_index_html_post (line 90) | def test_index_html_post(self):
method test_index_html_get (line 95) | def test_index_html_get(self):
method test_search_empty_html (line 100) | def test_search_empty_html(self):
method test_search_empty_json (line 105) | def test_search_empty_json(self):
method test_search_empty_csv (line 109) | def test_search_empty_csv(self):
method test_search_empty_rss (line 113) | def test_search_empty_rss(self):
method test_search_html (line 117) | def test_search_html(self):
method test_index_json (line 129) | def test_index_json(self):
method test_search_json (line 133) | def test_search_json(self):
method test_index_csv (line 142) | def test_index_csv(self):
method test_search_csv (line 146) | def test_search_csv(self):
method test_index_rss (line 155) | def test_index_rss(self):
method test_search_rss (line 159) | def test_search_rss(self):
method test_redirect_about (line 172) | def test_redirect_about(self):
method test_info_page (line 176) | def test_info_page(self):
method test_health (line 181) | def test_health(self):
method test_preferences (line 186) | def test_preferences(self):
method test_browser_locale (line 193) | def test_browser_locale(self):
method test_browser_empty_locale (line 207) | def test_browser_empty_locale(self):
method test_locale_occitan (line 214) | def test_locale_occitan(self):
method test_stats (line 221) | def test_stats(self):
method test_robots_txt (line 226) | def test_robots_txt(self):
method test_opensearch_xml (line 231) | def test_opensearch_xml(self):
method test_favicon (line 238) | def test_favicon(self):
method test_config (line 243) | def test_config(self):
FILE: tests/unit/test_webutils.py
class TestWebUtils (line 10) | class TestWebUtils(SearxTestCase):
method test_prettify_url (line 20) | def test_prettify_url(self, test_url: str, expected: str):
method test_highlight_content_none (line 31) | def test_highlight_content_none(self, content, query, expected):
method test_highlight_content_same (line 34) | def test_highlight_content_same(self):
method test_highlight_content_equal (line 77) | def test_highlight_content_equal(self, query: str, content: str, expec...
class TestUnicodeWriter (line 81) | class TestUnicodeWriter(SearxTestCase):
method setUp (line 83) | def setUp(self):
method test_write_row (line 87) | def test_write_row(self):
method test_write_rows (line 91) | def test_write_rows(self):
class TestNewHmac (line 98) | class TestNewHmac(SearxTestCase):
method test_attribute_error (line 106) | def test_attribute_error(self, secret_key):
method test_bytes (line 111) | def test_bytes(self):
FILE: utils/get_setting.py
function main (line 15) | def main(setting_name):
function get_setting_value (line 23) | def get_setting_value(settings, name):
function parse_yaml (line 34) | def parse_yaml(yaml_str):
Copy disabled (too large)
Download .json
Condensed preview — 905 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (14,871K chars).
[
{
"path": ".coveragerc",
"chars": 141,
"preview": "[run]\nbranch = True\nsource = searx\n\n[report]\nshow_missing = True\nexclude_lines =\n if __name__ == .__main__.:\n\n[html]\n"
},
{
"path": ".devcontainer/Dockerfile",
"chars": 704,
"preview": "ARG DEBIAN_CODENAME=\"bookworm\"\n\nFROM mcr.microsoft.com/devcontainers/base:$DEBIAN_CODENAME\n\nARG DEBIAN_CODENAME=\"bookwor"
},
{
"path": ".devcontainer/devcontainer.json",
"chars": 964,
"preview": "{\n \"build\": {\n \"args\": {\n \"DEBIAN_CODENAME\": \"bookworm\",\n },\n \"dockerfile\": \"Dockerfile\"\n },\n \"features"
},
{
"path": ".dir-locals-template.el",
"chars": 6854,
"preview": ";;; .dir-locals.el\n;;\n;; Per-Directory Local Variables:\n;; https://www.gnu.org/software/emacs/manual/html_node/emacs/D"
},
{
"path": ".dockerignore",
"chars": 57,
"preview": "*\n\n!container/entrypoint.sh\n!searx/**\n!requirements*.txt\n"
},
{
"path": ".editorconfig",
"chars": 1157,
"preview": "# https://editorconfig.org/\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\ninsert_final_newline = true\ntrim_trai"
},
{
"path": ".gitattributes",
"chars": 167,
"preview": "*.gif -diff\n*.png -diff\n*.min.css -diff\n*.min.js -diff\n*.css.map -diff\n*.js.map -diff\n*.eot -diff\n*.svg -diff\n*.ttf -dif"
},
{
"path": ".github/FUNDING.yml",
"chars": 67,
"preview": "github: [tiekoettercom]\ncustom: https://www.tiekoetter.com/donate/\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug-report.md",
"chars": 1352,
"preview": "---\nname: \"Bug report\"\nabout: Report a bug in SearXNG\"\nlabels: [\"bug\"]\ntype: \"bug\"\n---\n\n_Replace this placeholder with a"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 192,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Questions & Answers (Q&A)\n url: https://github.com/searxng/searx"
},
{
"path": ".github/ISSUE_TEMPLATE/engine-request.md",
"chars": 1314,
"preview": "---\nname: Engine request\"\nabout: Request a new engine in SearXNG\"\nlabels: [\"engine request\"]\ntype: \"feature\"\n---\n\n<!-- F"
},
{
"path": ".github/ISSUE_TEMPLATE/feature-request.md",
"chars": 938,
"preview": "---\nname: \"Feature request\"\nabout: \"Request a new feature in SearXNG\"\nlabels: [\"new feature\"]\ntype: \"feature\"\n---\n\n_Repl"
},
{
"path": ".github/dependabot.yml",
"chars": 1788,
"preview": "# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabo"
},
{
"path": ".github/workflows/container.yml",
"chars": 5924,
"preview": "---\nname: Container\n\n# yamllint disable-line rule:truthy\non:\n workflow_dispatch:\n workflow_run:\n workflows:\n -"
},
{
"path": ".github/workflows/data-update.yml",
"chars": 2592,
"preview": "---\nname: Update searx.data\n\n# yamllint disable-line rule:truthy\non:\n workflow_dispatch:\n schedule:\n - cron: \"59 23"
},
{
"path": ".github/workflows/documentation.yml",
"chars": 1856,
"preview": "---\nname: Documentation\n\n# yamllint disable-line rule:truthy\non:\n workflow_dispatch:\n push:\n branches:\n - mast"
},
{
"path": ".github/workflows/integration.yml",
"chars": 2695,
"preview": "---\nname: Integration\n\n# yamllint disable-line rule:truthy\non:\n push:\n branches:\n - master\n pull_request:\n "
},
{
"path": ".github/workflows/l10n.yml",
"chars": 4280,
"preview": "---\nname: Translation\n\n# yamllint disable-line rule:truthy\non:\n workflow_dispatch:\n workflow_run:\n workflows:\n "
},
{
"path": ".github/workflows/security.yml",
"chars": 1215,
"preview": "---\nname: Security\n\n# yamllint disable-line rule:truthy\non:\n workflow_dispatch:\n schedule:\n - cron: \"42 05 * * *\"\n\n"
},
{
"path": ".gitignore",
"chars": 274,
"preview": "# to sync with .dockerignore & pyrightconfig.json\n\n*.pyc\n*/*.pyc\n*~\n*.swp\ngeckodriver.log\n\n.coverage\ncoverage/\n\n.govm/\n."
},
{
"path": ".nvmrc",
"chars": 3,
"preview": "25\n"
},
{
"path": ".pylintrc",
"chars": 13244,
"preview": "# -*- coding: utf-8; mode: conf-unix -*-\n# lint Python modules using external checkers.\n#\n# This is the main checker con"
},
{
"path": ".vscode/launch.json",
"chars": 599,
"preview": "{\n // See https://go.microsoft.com/fwlink/?linkid=830387\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n "
},
{
"path": ".vscode/settings.json",
"chars": 215,
"preview": "{\n \"python.testing.unittestArgs\": [\n \"-v\",\n \"-s\",\n \"./tests\",\n \"-p\",\n \"test_*.py\"\n"
},
{
"path": ".vscode/tasks.json",
"chars": 955,
"preview": "{\n // See https://go.microsoft.com/fwlink/?LinkId=733558\n // for the documentation about the tasks.json format\n "
},
{
"path": ".weblate",
"chars": 82,
"preview": "[weblate]\nurl = https://translate.codeberg.org/api/\ntranslation = searxng/searxng\n"
},
{
"path": ".yamllint.yml",
"chars": 302,
"preview": "extends: default\n\nrules:\n\n indentation:\n spaces: 2\n\n # 120 chars should be enough, but don't fail if a line is long"
},
{
"path": "AI_POLICY.rst",
"chars": 2288,
"preview": ".. SPDX-License-Identifier: AGPL-3.0-or-later\n\nAI Policy\n=========\n\nRestrictions on Generative AI Usage\n----------------"
},
{
"path": "AUTHORS.rst",
"chars": 4272,
"preview": "searxng is a fork from `searx <https://github.com/searx/searx>`_ and is\nmaintained by Markus Heiser (`@return42 <https:/"
},
{
"path": "CHANGELOG.rst",
"chars": 462,
"preview": "=======\nSearXNG\n=======\n\nSearXNG development has been started in the middle of 2021 as a fork of the\nsearx project. Sin"
},
{
"path": "CONTRIBUTING.rst",
"chars": 3406,
"preview": ".. SPDX-License-Identifier: AGPL-3.0-or-later\n\n.. _Quickstart guide: https://docs.searxng.org/dev/quickstart.html\n.. _Co"
},
{
"path": "LICENSE",
"chars": 34520,
"preview": " GNU AFFERO GENERAL PUBLIC LICENSE\n Version 3, 19 November 2007\n\n Copyright (C)"
},
{
"path": "Makefile",
"chars": 2718,
"preview": "# -*- coding: utf-8; mode: makefile-gmake -*-\n# SPDX-License-Identifier: AGPL-3.0-or-later\n\n.DEFAULT_GOAL=help\nexport MT"
},
{
"path": "PULL_REQUEST_TEMPLATE.md",
"chars": 1052,
"preview": "<!-- FILL IN THESE FIELDS .. and delete the comments after reading.\n\n Use Markdown for formatting -> https://www.ma"
},
{
"path": "README.rst",
"chars": 2296,
"preview": ".. SPDX-License-Identifier: AGPL-3.0-or-later\n\n.. _metasearch engine: https://en.wikipedia.org/wiki/Metasearch_engine\n.."
},
{
"path": "SECURITY.md",
"chars": 353,
"preview": "# Security Policy\n\nWe love responsible reports of (potential) security issues in SearXNG.\n\nYou can contact us at securit"
},
{
"path": "babel.cfg",
"chars": 161,
"preview": "[extractors]\nsearxng_msg = searx.babel_extract.extract\n[ignore: **/node_modules/**]\n[python: **.py]\n[jinja2: **/template"
},
{
"path": "client/simple/.gitignore",
"chars": 18,
"preview": "dist\nnode_modules\n"
},
{
"path": "client/simple/.stylelintrc.json",
"chars": 657,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/stylelintrc.json\",\n \"plugins\": [\"stylelint-prettier\"],\n \"extends\": [\"styl"
},
{
"path": "client/simple/README.rst",
"chars": 356,
"preview": "=====================\nMEMO vite development\n=====================\n\nLocal install::\n\n # in folder ./client/simple/\n $ n"
},
{
"path": "client/simple/biome.json",
"chars": 4952,
"preview": "{\n \"$schema\": \"./node_modules/@biomejs/biome/configuration_schema.json\",\n \"files\": {\n \"ignoreUnknown\": true,\n \"i"
},
{
"path": "client/simple/generated/pygments.less",
"chars": 8962,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n this file is generated automatically by searxng_extra/update/update"
},
{
"path": "client/simple/package.json",
"chars": 1444,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/package.json\",\n \"name\": \"@searxng/theme-simple\",\n \"version\": \"0.0.0\",\n \""
},
{
"path": "client/simple/src/js/Plugin.ts",
"chars": 1602,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Base class for client-side plugins.\n *\n * @remarks\n * Handle condi"
},
{
"path": "client/simple/src/js/index.ts",
"chars": 124,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n// core\nvoid import.meta.glob([\"./*.ts\", \"./util/**/.ts\"], { eager: true "
},
{
"path": "client/simple/src/js/loader.ts",
"chars": 776,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport type { Plugin } from \"./Plugin.ts\";\nimport { type EndpointsKeys, e"
},
{
"path": "client/simple/src/js/main/autocomplete.ts",
"chars": 4332,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { http, listen, settings } from \"../toolkit.ts\";\nimport { assertEl"
},
{
"path": "client/simple/src/js/main/keyboard.ts",
"chars": 13174,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen, mutable, settings } from \"../toolkit.ts\";\nimport { asser"
},
{
"path": "client/simple/src/js/main/preferences.ts",
"chars": 2743,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { http, listen, settings } from \"../toolkit.ts\";\nimport { assertEl"
},
{
"path": "client/simple/src/js/main/results.ts",
"chars": 6148,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport \"../../../node_modules/swiped-events/src/swiped-events.js\";\nimport"
},
{
"path": "client/simple/src/js/main/search.ts",
"chars": 2923,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen } from \"../toolkit.ts\";\nimport { getElement } from \"../ut"
},
{
"path": "client/simple/src/js/plugin/Calculator.ts",
"chars": 2190,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport {\n absDependencies,\n addDependencies,\n create,\n divideDependen"
},
{
"path": "client/simple/src/js/plugin/InfiniteScroll.ts",
"chars": 3879,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { Plugin } from \"../Plugin.ts\";\nimport { http, settings } from \".."
},
{
"path": "client/simple/src/js/plugin/MapView.ts",
"chars": 2496,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport \"ol/ol.css\";\nimport { Feature, Map as OlMap, View } from \"ol\";\nimp"
},
{
"path": "client/simple/src/js/router.ts",
"chars": 1790,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { load } from \"./loader.ts\";\nimport { Endpoints, endpoint, listen,"
},
{
"path": "client/simple/src/js/toolkit.ts",
"chars": 3676,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport type { KeyBindingLayout } from \"./main/keyboard.ts\";\n\n// synced wi"
},
{
"path": "client/simple/src/js/util/appendAnswerElement.ts",
"chars": 1151,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { getElement } from \"./getElement.ts\";\n\nexport const appendAnswerE"
},
{
"path": "client/simple/src/js/util/assertElement.ts",
"chars": 283,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntype AssertElement = <T>(element?: T | null) => asserts element is T;\nexp"
},
{
"path": "client/simple/src/js/util/getElement.ts",
"chars": 539,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { assertElement } from \"./assertElement.ts\";\n\ntype Options = {\n a"
},
{
"path": "client/simple/src/less/animations.less",
"chars": 356,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.dialog-modal {\n animation-name: dialogmodal;\n animation-duration: 0.13"
},
{
"path": "client/simple/src/less/autocomplete.less",
"chars": 1226,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.autocomplete {\n position: absolute;\n width: @search-width;\n max-width"
},
{
"path": "client/simple/src/less/definitions.less",
"chars": 11085,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n * SearXNG, A privacy-respecting, hackable metasearch engine\n *\n * To "
},
{
"path": "client/simple/src/less/detail.less",
"chars": 5497,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n#main_results #results.image-detail-open.only_template_images {\n width: "
},
{
"path": "client/simple/src/less/embedded.less",
"chars": 998,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\niframe[src^=\"https://w.soundcloud.com\"] {\n height: 120px;\n}\n\niframe[src^"
},
{
"path": "client/simple/src/less/index.less",
"chars": 778,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n#main_index {\n margin-top: 26vh;\n}\n\n.index {\n text-align: center;\n\n .t"
},
{
"path": "client/simple/src/less/info.less",
"chars": 261,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.info-page {\n code {\n font-family: monospace;\n .rounded-corners-ti"
},
{
"path": "client/simple/src/less/mixins.less",
"chars": 689,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n// Mixins\n.text-size-adjust (@property: 100%) {\n text-size-adjust: @prop"
},
{
"path": "client/simple/src/less/preferences.less",
"chars": 4127,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntable {\n border-collapse: collapse;\n\n th,\n td {\n text-align: center"
},
{
"path": "client/simple/src/less/result_templates.less",
"chars": 114,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.osm-map-box {\n height: 300px;\n width: 100%;\n margin: 10px 0;\n}\n"
},
{
"path": "client/simple/src/less/result_types/code.less",
"chars": 995,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n@import \"../../../generated/pygments.less\";\n\n.codelines {\n margin: @resu"
},
{
"path": "client/simple/src/less/result_types/file.less",
"chars": 403,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n Layout of the Files result class\n*/\n\n#main_results .result-file {\n "
},
{
"path": "client/simple/src/less/result_types/keyvalue.less",
"chars": 647,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n Layout of the KeyValue result class\n*/\n\n#main_results .result-keyval"
},
{
"path": "client/simple/src/less/result_types/paper.less",
"chars": 1126,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n Layout of the Paper result class\n*/\n\n.result-paper {\n .attributes {"
},
{
"path": "client/simple/src/less/rss.less",
"chars": 658,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n@import (inline) \"../../node_modules/normalize.css/normalize.css\";\n@impor"
},
{
"path": "client/simple/src/less/search.less",
"chars": 7005,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n#search {\n padding: 0;\n margin: 0;\n}\n\n#search_header {\n padding-top: 1"
},
{
"path": "client/simple/src/less/stats.less",
"chars": 1686,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.engine-stats {\n border-spacing: 0;\n border-collapse: collapse;\n\n tr t"
},
{
"path": "client/simple/src/less/style-center.less",
"chars": 3302,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/*\n--center-page-width overrides the less variable @results-width when th"
},
{
"path": "client/simple/src/less/style-ltr.less",
"chars": 1322,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.ltr-left(@offset) {\n left: @offset;\n}\n\n.ltr-right(@offset) {\n right: @"
},
{
"path": "client/simple/src/less/style-rtl.less",
"chars": 2637,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.ltr-left(@offset) {\n right: @offset;\n}\n\n.ltr-right(@offset) {\n left: @"
},
{
"path": "client/simple/src/less/style.less",
"chars": 19320,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n// stylelint-disable no-descending-specificity\n\n@import (inline) \"../../n"
},
{
"path": "client/simple/src/less/toolkit.less",
"chars": 12308,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n// other solution : http://stackoverflow.com/questions/1577598/how-to-hi"
},
{
"path": "client/simple/src/less/toolkit_loader.less",
"chars": 645,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n.loader,\n.loader::after {\n border-radius: 50%;\n width: 10em;\n height: "
},
{
"path": "client/simple/src/less/weather.less",
"chars": 752,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n#answers .weather {\n summary {\n display: block;\n list-style: none;"
},
{
"path": "client/simple/theme_icons.ts",
"chars": 2652,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Generate icons.html for the jinja templates of the simple theme.\n "
},
{
"path": "client/simple/tools/img.ts",
"chars": 1927,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport sharp from"
},
{
"path": "client/simple/tools/jinja_svg_catalog.html.edge",
"chars": 750,
"preview": "{{--\nSPDX-License-Identifier: AGPL-3.0-or-later\n\nThis is a EDGE https://edgejs.dev/ template to generate a HTML Jinja te"
},
{
"path": "client/simple/tools/jinja_svg_catalog.ts",
"chars": 3474,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport fs from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\ni"
},
{
"path": "client/simple/tools/plg.ts",
"chars": 1324,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Custom vite plugins to build the web-client components of the simp"
},
{
"path": "client/simple/tsconfig.json",
"chars": 1115,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/tsconfig.json\",\n \"compilerOptions\": {\n \"lib\": [\"DOM\", \"DOM.Iterable\", \""
},
{
"path": "client/simple/vite.config.ts",
"chars": 5150,
"preview": "// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * CONFIG: https://vite.dev/config/\n */\n\nimport { resolve } from \"nod"
},
{
"path": "container/builder.dockerfile",
"chars": 1423,
"preview": "FROM ghcr.io/searxng/base:searxng-builder AS builder\n\nCOPY ./requirements.txt ./requirements-server.txt ./\n\nENV UV_NO_MA"
},
{
"path": "container/dist.dockerfile",
"chars": 1678,
"preview": "ARG CONTAINER_IMAGE_ORGANIZATION=\"searxng\"\nARG CONTAINER_IMAGE_NAME=\"searxng\"\n\nFROM localhost/$CONTAINER_IMAGE_ORGANIZAT"
},
{
"path": "container/docker-compose.yml",
"chars": 731,
"preview": "# Read the documentation before using the `docker-compose.yml` file:\n# https://docs.searxng.org/admin/installation-docke"
},
{
"path": "container/entrypoint.sh",
"chars": 2735,
"preview": "#!/bin/sh\n# shellcheck shell=dash\nset -u\n\n# Check if it's a valid file\ncheck_file() {\n local target=\"$1\"\n\n if [ ! "
},
{
"path": "docs/_static/searxng.css",
"chars": 935,
"preview": ".content {\n width: 52em; /* instead of 46em */\n}\n\np code.literal {\n text-wrap: nowrap;\n}\n\naside.sidebar {\n border"
},
{
"path": "docs/admin/answer-captcha.rst",
"chars": 1986,
"preview": "===============================\nAnswer CAPTCHA from server's IP\n===============================\n\nWith a SSH tunnel we ca"
},
{
"path": "docs/admin/api.rst",
"chars": 1971,
"preview": ".. _adminapi:\n\n==================\nAdministration API\n==================\n\nGet configuration data\n======================\n\n"
},
{
"path": "docs/admin/arch_public.dot",
"chars": 1161,
"preview": "digraph G {\n\n node [style=filled, shape=box, fillcolor=\"#ffffcc\", fontname=Sans];\n edge [fontname=\"Sans\"];\n\n browser "
},
{
"path": "docs/admin/architecture.rst",
"chars": 974,
"preview": ".. _architecture:\n\n============\nArchitecture\n============\n\n.. sidebar:: Further reading\n\n - Reverse Proxy: :ref:`Apach"
},
{
"path": "docs/admin/buildhosts.rst",
"chars": 3819,
"preview": ".. _buildhosts:\n\n==========\nBuildhosts\n==========\n\nTo get best results from build, it's recommend to install additional "
},
{
"path": "docs/admin/index.rst",
"chars": 430,
"preview": "===========================\nAdministrator documentation\n===========================\n\n.. toctree::\n :maxdepth: 2\n\n se"
},
{
"path": "docs/admin/installation-apache.rst",
"chars": 10921,
"preview": ".. _installation apache:\n\n======\nApache\n======\n\n.. _Apache: https://httpd.apache.org/\n.. _Apache Debian:\n https://cwi"
},
{
"path": "docs/admin/installation-docker.rst",
"chars": 9205,
"preview": ".. _installation container:\n\n======================\nInstallation container\n======================\n\n.. _Docker 101: https"
},
{
"path": "docs/admin/installation-granian.rst",
"chars": 1460,
"preview": ".. _searxng granian:\n\n=======\nGranian\n=======\n\n.. _Options: https://github.com/emmett-framework/granian/blob/master/READ"
},
{
"path": "docs/admin/installation-nginx.rst",
"chars": 6029,
"preview": ".. _installation nginx:\n\n=====\nNGINX\n=====\n\n.. _nginx:\n https://docs.nginx.com/nginx/admin-guide/\n.. _nginx server con"
},
{
"path": "docs/admin/installation-scripts.rst",
"chars": 1846,
"preview": ".. _installation scripts:\n\n===================\nInstallation Script\n===================\n\n.. sidebar:: Update the OS first"
},
{
"path": "docs/admin/installation-searxng.rst",
"chars": 3626,
"preview": ".. _installation basic:\n\n=========================\nStep by step installation\n=========================\n\nIn this section "
},
{
"path": "docs/admin/installation-uwsgi.rst",
"chars": 9171,
"preview": ".. _searxng uwsgi:\n\n=====\nuWSGI\n=====\n\n.. sidebar:: further reading\n\n - `systemd.unit`_\n - `uWSGI Emperor`_\n\n.. _sys"
},
{
"path": "docs/admin/installation.rst",
"chars": 701,
"preview": ".. _installation:\n\n============\nInstallation\n============\n\n*You're spoilt for choice*, choose your preferred method of i"
},
{
"path": "docs/admin/plugins.rst",
"chars": 543,
"preview": ".. _plugins admin:\n\n===============\nList of plugins\n===============\n\nFurther reading ..\n\n- :ref:`SearXNG settings <setti"
},
{
"path": "docs/admin/searx.favicons.rst",
"chars": 8822,
"preview": ".. _favicons:\n\n========\nFavicons\n========\n\n.. sidebar:: warning\n\n Don't activate the favicons before reading the docum"
},
{
"path": "docs/admin/searx.limiter.rst",
"chars": 170,
"preview": ".. _limiter:\n\n=======\nLimiter\n=======\n\n.. sidebar:: info\n\n The limiter requires a :ref:`Valkey <settings valkey>` data"
},
{
"path": "docs/admin/settings/index.rst",
"chars": 403,
"preview": ".. _searxng settings.yml:\n\n========\nSettings\n========\n\n.. sidebar:: Further reading ..\n\n - :ref:`engine settings`\n -"
},
{
"path": "docs/admin/settings/settings.rst",
"chars": 3005,
"preview": ".. _settings.yml:\n\n================\n``settings.yml``\n================\n\nThis page describe the options possibilities of t"
},
{
"path": "docs/admin/settings/settings_brand.rst",
"chars": 109,
"preview": ".. _settings brand:\n\n==========\n``brand:``\n==========\n\n.. autoclass:: searx.brand.SettingsBrand\n :members:\n"
},
{
"path": "docs/admin/settings/settings_categories_as_tabs.rst",
"chars": 917,
"preview": ".. _settings categories_as_tabs:\n\n=======================\n``categories_as_tabs:``\n=======================\n\nA list of the"
},
{
"path": "docs/admin/settings/settings_engines.rst",
"chars": 8762,
"preview": ".. _settings engines:\n\n============\n``engines:``\n============\n\n.. sidebar:: Further reading ..\n\n - :ref:`configured en"
},
{
"path": "docs/admin/settings/settings_general.rst",
"chars": 1474,
"preview": ".. _settings general:\n\n============\n``general:``\n============\n\n.. code:: yaml\n\n general:\n debug: false\n instan"
},
{
"path": "docs/admin/settings/settings_outgoing.rst",
"chars": 4397,
"preview": ".. _settings outgoing:\n\n=============\n``outgoing:``\n=============\n\nCommunication with search engines.\n\n.. code:: yaml\n\n "
},
{
"path": "docs/admin/settings/settings_plugins.rst",
"chars": 3015,
"preview": ".. _settings plugins:\n\n============\n``plugins:``\n============\n\n.. attention::\n\n The ``enabled_plugins:`` section in Se"
},
{
"path": "docs/admin/settings/settings_redis.rst",
"chars": 820,
"preview": ".. _settings redis:\n\n==========\n``redis:``\n==========\n\n.. _Valkey: https://valkey.io\n\n.. attention::\n\n SearXNG is swit"
},
{
"path": "docs/admin/settings/settings_search.rst",
"chars": 2854,
"preview": ".. _settings search:\n\n===========\n``search:``\n===========\n\n.. code:: yaml\n\n search:\n safe_search: 0\n autocompl"
},
{
"path": "docs/admin/settings/settings_server.rst",
"chars": 2678,
"preview": ".. _settings server:\n\n===========\n``server:``\n===========\n\n.. code:: yaml\n\n server:\n base_url: http://example.or"
},
{
"path": "docs/admin/settings/settings_ui.rst",
"chars": 2066,
"preview": ".. _settings ui:\n\n=======\n``ui:``\n=======\n\n.. _cache busting:\n https://developer.mozilla.org/en-US/docs/Web/HTTP/Heade"
},
{
"path": "docs/admin/settings/settings_valkey.rst",
"chars": 1595,
"preview": ".. _settings valkey:\n\n===========\n``valkey:``\n===========\n\n.. _Valkey:\n https://valkey.io\n.. _Valkey-Installation:\n "
},
{
"path": "docs/admin/update-searxng.rst",
"chars": 2509,
"preview": ".. _searxng maintenance:\n\n===================\nSearXNG maintenance\n===================\n\n.. sidebar:: further read\n\n - :"
},
{
"path": "docs/build-templates/searxng.rst",
"chars": 4495,
"preview": ".. template evaluated by: ./utils/searxng.sh searxng.doc.rst\n.. hint: all dollar-names are variables, dollar sign itself"
},
{
"path": "docs/conf.py",
"chars": 7502,
"preview": "# SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport os\nfrom pathlib import Path\n\nfrom searx import get_setting\nfrom sea"
},
{
"path": "docs/dev/answerers/builtins.rst",
"chars": 136,
"preview": ".. _builtin answerers:\n\n==================\nBuilt-in Answerers\n==================\n\n.. toctree::\n :maxdepth: 1\n\n rando"
},
{
"path": "docs/dev/answerers/development.rst",
"chars": 116,
"preview": ".. _dev answerers:\n\n====================\nAnswerer Development\n====================\n\n.. automodule:: searx.answerers\n"
},
{
"path": "docs/dev/answerers/index.rst",
"chars": 88,
"preview": "=========\nAnswerers\n=========\n\n.. toctree::\n :maxdepth: 2\n\n development\n builtins\n"
},
{
"path": "docs/dev/answerers/random.rst",
"chars": 108,
"preview": ".. _answerer.random:\n\n======\nRandom\n======\n\n.. autoclass:: searx.answerers.random.SXNGAnswerer\n :members:\n"
},
{
"path": "docs/dev/answerers/statistics.rst",
"chars": 128,
"preview": ".. _answerer.statistics:\n\n==========\nStatistics\n==========\n\n.. autoclass:: searx.answerers.statistics.SXNGAnswerer\n :m"
},
{
"path": "docs/dev/commits.rst",
"chars": 4149,
"preview": ".. _create commit:\n\n===============================\nGit Commits & Change Management\n===============================\n\n.. "
},
{
"path": "docs/dev/contribution_guide.rst",
"chars": 5116,
"preview": ".. _how to contribute:\n\n=================\nHow to contribute\n=================\n\nPrime directives: Privacy, Hackability\n=="
},
{
"path": "docs/dev/csv_table.txt",
"chars": 384,
"preview": "stub col row 1, column, \"loremLorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy\neirmod tempor inv"
},
{
"path": "docs/dev/engines/demo/demo_offline.rst",
"chars": 143,
"preview": ".. _demo offline engine:\n\n===================\nDemo Offline Engine\n===================\n\n.. automodule:: searx.engines.dem"
},
{
"path": "docs/dev/engines/demo/demo_online.rst",
"chars": 138,
"preview": ".. _demo online engine:\n\n==================\nDemo Online Engine\n==================\n\n.. automodule:: searx.engines.demo_on"
},
{
"path": "docs/dev/engines/engine_overview.rst",
"chars": 11431,
"preview": ".. _engines-dev:\n\n===============\nEngine Overview\n===============\n\n.. _metasearch-engine: https://en.wikipedia.org/wiki/"
},
{
"path": "docs/dev/engines/enginelib.rst",
"chars": 224,
"preview": ".. _searx.enginelib:\n\n==============\nEngine Library\n==============\n\n.. automodule:: searx.enginelib\n :members:\n\n.. _se"
},
{
"path": "docs/dev/engines/engines.rst",
"chars": 146,
"preview": ".. _searx.engines loader:\n\n========================\nSearXNG's engines loader\n========================\n\n.. automodule:: s"
},
{
"path": "docs/dev/engines/index.rst",
"chars": 1906,
"preview": ".. _engine implementations:\n\n======================\nEngine Implementations\n======================\n\n.. toctree::\n :capt"
},
{
"path": "docs/dev/engines/json_engine.rst",
"chars": 118,
"preview": ".. _json_engine engine:\n\n============\nJSON Engine\n============\n\n.. automodule:: searx.engines.json_engine\n :members:\n"
},
{
"path": "docs/dev/engines/mediawiki.rst",
"chars": 127,
"preview": ".. _mediawiki engine:\n\n================\nMediaWiki Engine\n================\n\n.. automodule:: searx.engines.mediawiki\n :me"
},
{
"path": "docs/dev/engines/offline/command-line-engines.rst",
"chars": 385,
"preview": ".. _engine command:\n\n====================\nCommand Line Engines\n====================\n\n.. sidebar:: info\n\n - :origin:`co"
},
{
"path": "docs/dev/engines/offline/nosql-engines.rst",
"chars": 2393,
"preview": ".. _nosql engines:\n\n===============\nNoSQL databases\n===============\n\n.. sidebar:: further read\n\n - `NoSQL database <ht"
},
{
"path": "docs/dev/engines/offline/search-indexer-engines.rst",
"chars": 1395,
"preview": "=================\nLocal Search APIs\n=================\n\n.. sidebar:: further read\n\n - `Comparison to alternatives\n "
},
{
"path": "docs/dev/engines/offline/sql-engines.rst",
"chars": 3438,
"preview": ".. _sql engines:\n\n===========\nSQL Engines\n===========\n\n.. sidebar:: further read\n\n - `SQLite <https://www.sqlite.org/i"
},
{
"path": "docs/dev/engines/offline_concept.rst",
"chars": 2644,
"preview": "===============\nOffline Concept\n===============\n\n.. sidebar:: offline engines\n\n - :ref:`demo offline engine`\n - :ref"
},
{
"path": "docs/dev/engines/online/adobe_stock.rst",
"chars": 117,
"preview": ".. _adobe stock engine:\n\n===========\nAdobe Stock\n===========\n\n.. automodule:: searx.engines.adobe_stock\n :members:\n"
},
{
"path": "docs/dev/engines/online/alpinelinux.rst",
"chars": 147,
"preview": ".. _alpinelinux engine:\n\n=====================\nAlpine Linux Packages\n=====================\n\n.. automodule:: searx.engine"
},
{
"path": "docs/dev/engines/online/annas_archive.rst",
"chars": 130,
"preview": ".. _annas_archive engine:\n\n==============\nAnna's Archive\n==============\n\n.. automodule:: searx.engines.annas_archive\n "
},
{
"path": "docs/dev/engines/online/aol.rst",
"chars": 77,
"preview": ".. _aol engine:\n\n===\nAOL\n===\n\n.. automodule:: searx.engines.aol\n :members:\n"
},
{
"path": "docs/dev/engines/online/archlinux.rst",
"chars": 110,
"preview": ".. _archlinux engine:\n\n==========\nArch Linux\n==========\n\n.. automodule:: searx.engines.archlinux\n :members:\n\n"
},
{
"path": "docs/dev/engines/online/arxiv.rst",
"chars": 87,
"preview": ".. _arxiv engine:\n\n=====\narXiv\n=====\n\n.. automodule:: searx.engines.arxiv\n :members:\n"
},
{
"path": "docs/dev/engines/online/astrophysics_data_system.rst",
"chars": 200,
"preview": ".. _astrophysics_data_system engine:\n\n==============================\nAstrophysics Data System (ADS)\n===================="
},
{
"path": "docs/dev/engines/online/azure.rst",
"chars": 117,
"preview": ".. _azure engine:\n\n===============\nAzure Resources\n===============\n\n.. automodule:: searx.engines.azure\n :members:\n"
},
{
"path": "docs/dev/engines/online/bing.rst",
"chars": 454,
"preview": ".. _bing engines:\n\n============\nBing Engines\n============\n\n.. _bing web engine:\n\nBing WEB\n========\n\n.. automodule:: sear"
},
{
"path": "docs/dev/engines/online/bpb.rst",
"chars": 76,
"preview": ".. _bpb engine:\n\n===\nBpb\n===\n\n.. automodule:: searx.engines.bpb\n :members:\n"
},
{
"path": "docs/dev/engines/online/brave.rst",
"chars": 574,
"preview": "=============\nBrave Engines\n=============\n\nBrave offers two different engines for SearXNG:\n\n1. The standard engine (``br"
},
{
"path": "docs/dev/engines/online/bt4g.rst",
"chars": 82,
"preview": ".. _bt4g engine:\n\n====\nBT4G\n====\n\n.. automodule:: searx.engines.bt4g\n :members:\n\n"
},
{
"path": "docs/dev/engines/online/cara.rst",
"chars": 103,
"preview": ".. _cara engine:\n\n===========\nCara Images\n===========\n\n.. automodule:: searx.engines.cara\n :members:\n"
},
{
"path": "docs/dev/engines/online/chinaso.rst",
"chars": 97,
"preview": ".. _chinaso engine:\n\n=======\nChinaSo\n=======\n\n.. automodule:: searx.engines.chinaso\n :members:\n"
},
{
"path": "docs/dev/engines/online/core.rst",
"chars": 82,
"preview": ".. _core engine:\n\n====\nCORE\n====\n\n.. automodule:: searx.engines.core\n :members:\n"
},
{
"path": "docs/dev/engines/online/crossref.rst",
"chars": 102,
"preview": ".. _crossref engine:\n\n========\nCrossref\n========\n\n.. automodule:: searx.engines.crossref\n :members:\n"
},
{
"path": "docs/dev/engines/online/dailymotion.rst",
"chars": 116,
"preview": ".. _dailymotion engine:\n\n===========\nDailymotion\n===========\n\n.. automodule:: searx.engines.dailymotion\n :members:\n"
},
{
"path": "docs/dev/engines/online/discourse.rst",
"chars": 128,
"preview": ".. _discourse engine:\n\n================\nDiscourse Forums\n================\n\n.. automodule:: searx.engines.discourse\n :m"
},
{
"path": "docs/dev/engines/online/duckduckgo.rst",
"chars": 328,
"preview": ".. _duckduckgo engines:\n\n==================\nDuckDuckGo Engines\n==================\n\n.. automodule:: searx.engines.duckduc"
},
{
"path": "docs/dev/engines/online/geizhals.rst",
"chars": 100,
"preview": ".. _gitea geizhals:\n\n========\nGeizhals\n========\n\n.. automodule:: searx.engines.geizhals\n :members:\n"
},
{
"path": "docs/dev/engines/online/gitea.rst",
"chars": 86,
"preview": ".. _gitea engine:\n\n=====\nGitea\n=====\n\n.. automodule:: searx.engines.gitea\n :members:\n"
},
{
"path": "docs/dev/engines/online/github_code.rst",
"chars": 117,
"preview": ".. _github code engine:\n\n===========\nGithub Code\n===========\n\n.. automodule:: searx.engines.github_code\n :members:\n"
},
{
"path": "docs/dev/engines/online/gitlab.rst",
"chars": 92,
"preview": ".. _gitlab engine:\n\n======\nGitLab\n======\n\n.. automodule:: searx.engines.gitlab\n :members:\n"
},
{
"path": "docs/dev/engines/online/google.rst",
"chars": 1388,
"preview": ".. _google engines:\n\n==============\nGoogle Engines\n==============\n\n.. _google API:\n\nGoogle API\n==========\n\n.. _Query Par"
},
{
"path": "docs/dev/engines/online/huggingface.rst",
"chars": 120,
"preview": ".. _huggingface engine:\n\n============\nHugging Face\n============\n\n.. automodule:: searx.engines.huggingface\n :members:\n"
},
{
"path": "docs/dev/engines/online/karmasearch.rst",
"chars": 117,
"preview": ".. _karmasearch engine:\n\n===========\nKarmasearch\n===========\n\n.. automodule:: searx.engines.karmasearch\n :members:\n"
},
{
"path": "docs/dev/engines/online/lemmy.rst",
"chars": 87,
"preview": ".. _lemmy engine:\n\n=====\nLemmy\n=====\n\n.. automodule:: searx.engines.lemmy\n :members:\n"
},
{
"path": "docs/dev/engines/online/loc.rst",
"chars": 124,
"preview": ".. _loc engine:\n\n===================\nLibrary of Congress\n===================\n\n.. automodule:: searx.engines.loc\n :membe"
},
{
"path": "docs/dev/engines/online/marginalia.rst",
"chars": 133,
"preview": ".. _marginalia engine:\n\n=================\nMarginalia Search\n=================\n\n.. automodule:: searx.engines.marginalia\n"
},
{
"path": "docs/dev/engines/online/mastodon.rst",
"chars": 101,
"preview": ".. _mastodon engine:\n\n========\nMastodon\n========\n\n.. automodule:: searx.engines.mastodon\n :members:\n"
},
{
"path": "docs/dev/engines/online/moviepilot.rst",
"chars": 112,
"preview": ".. _moviepilot engine:\n\n==========\nMoviepilot\n==========\n\n.. automodule:: searx.engines.moviepilot\n :members:\n"
},
{
"path": "docs/dev/engines/online/mrs.rst",
"chars": 143,
"preview": ".. _mrs engine:\n\n=========================\nMatrix Rooms Search (MRS)\n=========================\n\n.. automodule:: searx.en"
},
{
"path": "docs/dev/engines/online/mwmbl.rst",
"chars": 260,
"preview": ".. _Mwmbl engine:\n\n============\nMwmbl Engine\n============\n\n.. _mwmbl web engine:\n\nMwmbl WEB\n=========\n\n.. automodule:: s"
},
{
"path": "docs/dev/engines/online/odysee.rst",
"chars": 91,
"preview": ".. _odysee engine:\n\n======\nOdysee\n======\n\n.. automodule:: searx.engines.odysee\n :members:\n"
},
{
"path": "docs/dev/engines/online/openalex.rst",
"chars": 102,
"preview": ".. _openalex engine:\n\n========\nOpenAlex\n========\n\n.. automodule:: searx.engines.openalex\n :members:\n"
},
{
"path": "docs/dev/engines/online/openlibrary.rst",
"chars": 120,
"preview": ".. _openlibrary engine:\n\n============\nOpen Library\n============\n\n.. automodule:: searx.engines.openlibrary\n :members:\n"
},
{
"path": "docs/dev/engines/online/peertube.rst",
"chars": 290,
"preview": ".. _peertube engines:\n\n================\nPeertube Engines\n================\n\n.. _peertube video engine:\n\nPeertube Video\n=="
},
{
"path": "docs/dev/engines/online/piped.rst",
"chars": 86,
"preview": ".. _piped engine:\n\n=====\nPiped\n=====\n\n.. automodule:: searx.engines.piped\n :members:\n"
},
{
"path": "docs/dev/engines/online/presearch.rst",
"chars": 128,
"preview": ".. _engine presearch:\n\n================\nPresearch Engine\n================\n\n.. automodule:: searx.engines.presearch\n :m"
},
{
"path": "docs/dev/engines/online/pubmed.rst",
"chars": 92,
"preview": ".. _pubmed engine:\n\n======\nPubMed\n======\n\n.. automodule:: searx.engines.pubmed\n :members:\n"
},
{
"path": "docs/dev/engines/online/qwant.rst",
"chars": 87,
"preview": ".. _qwant engine:\n\n=====\nQwant\n=====\n\n.. automodule:: searx.engines.qwant\n :members:\n"
},
{
"path": "docs/dev/engines/online/radio_browser.rst",
"chars": 123,
"preview": ".. _RadioBrowser engine:\n\n============\nRadioBrowser\n============\n\n.. automodule:: searx.engines.radio_browser\n :member"
},
{
"path": "docs/dev/engines/online/recoll.rst",
"chars": 113,
"preview": ".. _engine recoll:\n\n=============\nRecoll Engine\n=============\n\n.. automodule:: searx.engines.recoll\n :members:\n"
},
{
"path": "docs/dev/engines/online/repology.rst",
"chars": 102,
"preview": ".. _repology engine:\n\n========\nRepology\n========\n\n.. automodule:: searx.engines.repology\n :members:\n"
},
{
"path": "docs/dev/engines/online/reuters.rst",
"chars": 97,
"preview": ".. _reuters engine:\n\n=======\nReuters\n=======\n\n.. automodule:: searx.engines.reuters\n :members:\n"
},
{
"path": "docs/dev/engines/online/semantic_scholar.rst",
"chars": 142,
"preview": ".. _semantic_scholar engine:\n\n================\nSemantic Scholar\n================\n\n.. automodule:: searx.engines.semantic"
},
{
"path": "docs/dev/engines/online/soundcloud.rst",
"chars": 112,
"preview": ".. _soundcloud engine:\n\n==========\nSoundcloud\n==========\n\n.. automodule:: searx.engines.soundcloud\n :members:\n"
},
{
"path": "docs/dev/engines/online/sourcehut.rst",
"chars": 107,
"preview": ".. _sourcehut engine:\n\n=========\nSourcehut\n=========\n\n.. automodule:: searx.engines.sourcehut\n :members:\n"
},
{
"path": "docs/dev/engines/online/springer.rst",
"chars": 123,
"preview": ".. _springer engine:\n\n===============\nSpringer Nature\n===============\n\n.. automodule:: searx.engines.springer\n :member"
},
{
"path": "docs/dev/engines/online/startpage.rst",
"chars": 132,
"preview": ".. _startpage engines:\n\n=================\nStartpage Engines\n=================\n\n.. automodule:: searx.engines.startpage\n "
},
{
"path": "docs/dev/engines/online/tagesschau.rst",
"chars": 123,
"preview": ".. _tagesschau engine:\n\n==============\nTagesschau API\n==============\n\n.. automodule:: searx.engines.tagesschau\n :member"
}
]
// ... and 705 more files (download for full content)
About this extraction
This page contains the full source code of the tiekoetter/searxng GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 905 files (12.5 MB), approximately 3.3M tokens, and a symbol index with 2157 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.