Compare commits

..

85 commits

Author SHA1 Message Date
7182190057 Merge pull request 'master' (#2) from Icycoide/searxng:master into master
Reviewed-on: #2
2025-05-31 13:31:47 +02:00
benpiano800
37d851fb23 [mod] UI footer: correct capitalization of "SearXNG" in base.html 2025-05-30 09:33:57 +02:00
dependabot[bot]
1b424b8d54 [upd] pypi: Bump the minor group with 2 updates
Bumps the minor group with 2 updates: [selenium](https://github.com/SeleniumHQ/Selenium) and [typer-slim](https://github.com/fastapi/typer).


Updates `selenium` from 4.32.0 to 4.33.0
- [Release notes](https://github.com/SeleniumHQ/Selenium/releases)
- [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.32.0...selenium-4.33.0)

Updates `typer-slim` from 0.15.4 to 0.16.0
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](https://github.com/fastapi/typer/compare/0.15.4...0.16.0)

---
updated-dependencies:
- dependency-name: selenium
  dependency-version: 4.33.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: typer-slim
  dependency-version: 0.16.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 09:23:11 +02:00
dependabot[bot]
b991688fcb [upd] web-client (simple): Bump the minor group
Bumps the minor group in /client/simple with 2 updates: [globals](https://github.com/sindresorhus/globals) and [stylelint](https://github.com/stylelint/stylelint).


Updates `globals` from 16.1.0 to 16.2.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v16.1.0...v16.2.0)

Updates `stylelint` from 16.19.1 to 16.20.0
- [Release notes](https://github.com/stylelint/stylelint/releases)
- [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/stylelint/stylelint/compare/16.19.1...16.20.0)

---
updated-dependencies:
- dependency-name: globals
  dependency-version: 16.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: stylelint
  dependency-version: 16.20.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-30 09:16:49 +02:00
searxng-bot
44471bef35 [l10n] update translations from Weblate
0f55f2438 - 2025-05-29 - sandijs <sandijs@noreply.codeberg.org>
109f7dcb8 - 2025-05-26 - ngf <ngf@noreply.codeberg.org>
d2ba9b3d0 - 2025-05-26 - artnay <artnay@noreply.codeberg.org>
33c6f23bf - 2025-05-26 - realkendrick_fr <realkendrick_fr@noreply.codeberg.org>
2025-05-30 09:13:36 +02:00
dependabot[bot]
0b4c47a123 [upd] web-client (simple): Bump the minor group
Bumps the minor group in /client/simple with 4 updates: [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js), [eslint](https://github.com/eslint/eslint), [sharp](https://github.com/lovell/sharp) and [webpack](https://github.com/webpack/webpack).


Updates `@eslint/js` from 9.26.0 to 9.27.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.27.0/packages/js)

Updates `eslint` from 9.26.0 to 9.27.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.26.0...v9.27.0)

Updates `sharp` from 0.34.1 to 0.34.2
- [Release notes](https://github.com/lovell/sharp/releases)
- [Commits](https://github.com/lovell/sharp/compare/v0.34.1...v0.34.2)

Updates `webpack` from 5.99.8 to 5.99.9
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.99.8...v5.99.9)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.27.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: eslint
  dependency-version: 9.27.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: sharp
  dependency-version: 0.34.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: webpack
  dependency-version: 5.99.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-29 09:00:15 +02:00
Markus Heiser
913dfbde3c [fix] plugins: currency processor bug
Fix C&P typo from  https://github.com/searxng/searxng/pull/4836

Closes: https://github.com/searxng/searxng/issues/4861
2025-05-29 07:37:59 +02:00
searxng-bot
7448a18efa [data] update searx.data - update_ahmia_blacklist.py 2025-05-29 07:11:55 +02:00
searxng-bot
23396f5a1d [data] update searx.data - update_firefox_version.py 2025-05-29 07:10:22 +02:00
searxng-bot
dbe6a6f4fa [data] update searx.data - update_wikidata_units.py 2025-05-29 07:08:32 +02:00
searxng-bot
b2727e1be9 [data] update searx.data - update_currencies.py 2025-05-29 07:07:55 +02:00
searxng-bot
9d8592afd7 [data] update searx.data - update_engine_traits.py 2025-05-29 07:07:05 +02:00
searxng-bot
70a387a48f [data] update searx.data - update_engine_descriptions.py 2025-05-29 07:06:38 +02:00
Bnyro
2288f07d62 [fix] presearch: reuse response cookies from token extraction
Why?
- presearch requires the response cookies of the first request to be sent within the second request
- otherwise we miss auth information and the engine doesn't work

Related:
- https://github.com/searxng/searxng/pull/4858
- closes https://github.com/searxng/searxng/issues/4854

Co-authored-by: Aadniz <8147434+Aadniz@users.noreply.github.com>
2025-05-28 12:53:45 +02:00
Bnyro
20b40351b9 [chore] il post: disable by default 2025-05-26 17:39:09 +02:00
Bnyro
7a5a499795 [build] /static 2025-05-25 18:04:18 +02:00
Bnyro
9dfdd30da0 [fix] search: autocomplete focus on results page
This has been a regression introduced with the removal of
the unmaintained autocomplete.js library.

We should only focus the search bar on the main search page at `/`
and not at the results page located at `/search`.

I'm not sure if there's a better way to figure out if
we're on the results page than checking if the id of the
main element is `#main_results`, checking the path
obviously isn't a better solution because it can differ
depending on the instance / reverse proxy / ....

- related to 32823ecb69
- closes https://github.com/searxng/searxng/issues/4846
2025-05-25 18:04:18 +02:00
Ivan Gabaldon
14b8a999f3
[mod] ci: exclude some workflows from forks (#4849)
Excludes some workflows/jobs unneeded on forks.

Closes https://github.com/searxng/searxng/issues/4847
2025-05-25 14:54:27 +02:00
Markus Heiser
848c8d0544
[mod] data: implement a simple currencies (SQL) database (#4836)
To reduce the memory footprint, this patch no longer loads the JSON data
completely into memory.  Instead, there is an SQL database based on
`ExpireCacheSQLite`.

The class CurrenciesDB is a simple DB application that encapsulates the
DB (queries and initialization) and provides convenient methods like
`name_to_iso4217` and `iso4217_to_name`.

Related:

- https://github.com/searxng/searxng/discussions/1892
- https://github.com/searxng/searxng/pull/3458#issuecomment-2900807671
- https://github.com/searxng/searxng/pull/4650

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-25 10:40:57 +02:00
github-actions[bot]
e46187e3ce
[l10n] update translations from Weblate (#4840)
51e0a154c - 2025-05-22 - Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>
256b8cb8e - 2025-05-16 - wetinee <wetinee@noreply.codeberg.org>
ac12b76a8 - 2025-05-16 - wetinee <wetinee@noreply.codeberg.org>

Co-authored-by: searxng-bot <searxng-bot@users.noreply.github.com>
2025-05-25 10:36:27 +02:00
Markus Heiser
064eb50473
[mod] engines: Yahoo in different languages (#4826)
BTW fix issue reported in [1]

[1] https://github.com/searxng/searxng/pull/4814#issuecomment-2896948787

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
Co-authored-by: Bnyro <bnyro@tutanota.com>
2025-05-24 13:14:13 +02:00
Alexandre Flament
9ed9a9aa53
[fix] searx.network: don't trigger DeprecationWarning (#4845)
Avoid a confusing warning:

    DeprecationWarning: Setting per-request cookies=<...> is being deprecated

Code based on httpx unit test [1]

[1] 6a99f6f2b3/tests/client/test_cookies.py (L123-L137)

Closes: https://github.com/searxng/searxng/issues/4833
2025-05-24 12:40:05 +02:00
Markus Heiser
230215c250
[fix] preferences: description not localized for all UI languages (#4844)
The previous implementation for determining the description of an engine did not
take into account that the UI languages ​​can also have a region tag and/or a
script tag:

    el-GR:      Ελληνικά, Ελλάδα (Greek, Greece)
    fa-IR:      فارسی, ایران (Persian, Iran)
    nb-NO:      Norsk bokmål, Norge (Norwegian bokmål, Norway)
    nl-BE:      Nederlands, België (Dutch, Belgium)
    pt-BR:      Português, Brasil (Portuguese, Brazil)
    zh-HK:      中文, 中國香港特別行政區 (Chinese, Hong Kong SAR China)
    zh-Hans-CN: 中文, 中国 (Chinese, China)
    zh-Hant-TW: 中文, 台灣 (Chinese, Taiwan)

Closes: https://github.com/searxng/searxng/issues/4842

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-23 17:11:41 +02:00
Markus Heiser
1ef5c03962
[fix] ddg engine: IndexError exception is raised on empty contend (#4843)
Sometimes (e.g. when ddg does not have a result item) there is no content and
the engine will fail with an IndexError:

  * Error: IndexError
  * Percentage: 10
  * Parameters: `()`
  * File name: `searx/engines/duckduckgo.py:375`
  * Function: `response`
  * Code: `item["content"] = extract_text(eval_xpath(div_result, './/a[contains(@class, "result__snippet")]')[0])`

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-23 14:55:22 +02:00
useralias
4fa7de8033
[refactor] duckduckgo engine: improve request logic and code structure (#4837)
Changes:
- Add trailing slash to base URL to prevent potential redirects
- Remove advanced search syntax filtering (no longer guarantees a CAPTCHA)
- Correct pagination offset calculation: Page 2 now starts at offset 10,
  subsequent pages use 10 + (n-2)*15 formula instead of the previous
  broken 20 + (n-2)*50 calculation that caused CAPTCHAs
- Restructure request parameter building to better match a real request
- "kt" cookie is no longer an empty string if the language/region is "all"
- Group related parameter assignments together
- Add header logging to debugging output

Related:

- https://github.com/searxng/searxng/issues/4824
2025-05-23 13:01:10 +02:00
Markus Heiser
98badc9cd0
[fix] searx.data: fetch-traits - z-library (httpx.ConnectError) (#4835)
There is currently no known z-library, and all known URLs are dead [1]. To avoid
interrupting automated updates, a connection error to a z-library is treated as
a *known error*, and the old properties of the z-library are retained.

[1] https://github.com/searxng/searxng/issues/3610

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-22 17:43:11 +02:00
Markus Heiser
d29cf64ce4
[mod] searx.data: lazy load of the data objects (databases) (#4834)
In the previous implementation, all databases were loaded into memory when
importing the searx.data package, regardless of whether they were ever needed.

Regardless of this, it is an antipattern to load entire databases into memory
when importing a package or module; databases should be loaded when needed.

Lazy loading is a first step toward improving memory usage and also improves
performance when setting up the runtime environment.  Building on this,
subsequent PRs will be able to further optimize memory behavior, e.g., by using
a real database application such as the one already available via

    searx.cache.ExpireCache

Related:

- https://github.com/searxng/searxng/discussions/1892
- https://github.com/searxng/searxng/pull/3458
- https://github.com/searxng/searxng/pull/4650

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-22 16:23:30 +02:00
Markus Heiser
861f9c4be5 [build] /static 2025-05-22 15:16:54 +02:00
Bnyro
32823ecb69 [refactor] search.js: use custom auto completion implementation
The previously used library is unmaintained for 6 years now [1] and the solution
had know issues [2][3]

[1] https://github.com/searxng/searxng/pull/4284#discussion_r1954493434
[2] https://github.com/searxng/searxng/pull/4318#issuecomment-2731576657
[3] https://github.com/privau/searxng/issues/56
2025-05-22 15:16:54 +02:00
Zhijie He
156d1eb8c8
[feat] engines: add Naver engine (#4573)
Refactor Naver engine (Web, News, Images, Videos, Autocomplete)

- ref: https://search.naver.com/
- lang: `ko`
- Wikidata: https://www.wikidata.org/wiki/Q485639

Co-authored-by: Bnyro <bnyro@tutanota.com>
2025-05-21 18:25:02 +02:00
Markus Heiser
365b9426f1
[fix] engines: disable those with known issues (#4813)
- z-library https://github.com/searxng/searxng/issues/3610
- library of congress: https://github.com/searxng/searxng/issues/4810
- qwant: https://github.com/searxng/searxng/issues/3929

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-21 15:50:29 +02:00
Ivan Gabaldon
9ffe23ecf3 [mod] container: remove -e flag
Temporarily remove the -e flag from set to prevent entrypoint.sh from stopping execution if any command returns a non-zero status. This doesn't solve anything but relaxes the script checks.

Related https://github.com/searxng/searxng/issues/4818
2025-05-21 15:27:26 +02:00
Bnyro
502017b901
[fix] pinterest: engine broken due to API changes (#4816)
- apparently the API now requires a `X-Pinterest-PWS-Handler` in order to
  properly function (extracted from their web UI)

- the other `X-Pinterest` headers here are added in case they become mandatory
  too

Closes: https://github.com/searxng/searxng/issues/4812
2025-05-21 15:22:42 +02:00
Bnyro
88973f5431
[feat] engines: add uxwing engine for icons (#4819)
- uxwing provides attribution-free icons to use for design projects
- svgrepo was my go-to before, but it's ratelimiting a lot recently
2025-05-21 15:10:29 +02:00
Bnyro
8bff73c9b6
[refactor] icon engines: add new icon category (#4817)
Icons category makes sense because it allows to quickly search for free SVG
icons to use for websites / other designs with a quick `!icons` query

Icons don't seem to fit into the normal images category that well because icons
are quite a special type of images
2025-05-21 14:52:16 +02:00
Jost Alemann
7420706a50
[chore] fix some docstring typos (#4815) 2025-05-20 21:03:54 +02:00
useralias
6ec554cb5b [fix] yahoo: url and title xpath 2025-05-20 21:02:40 +02:00
Alexandre Flament
7a3742ae56
[mod] upgrade to httpx 0.28.1 (#4674) 2025-05-20 18:18:07 +02:00
Markus Heiser
ca67f1dffe
[fix] duckduckgo engines: issue when get_vqd() is used by ddg-images and ddg-videos (#4809)
The global variable CACHE is not initialized when DDG images or DDG videos
import the get_vqd() function (please remember: the engine modules are imported
using the importlib method and not via the `import` keyword).

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-20 16:10:10 +02:00
Ivan Gabaldon
749de829d5 [mod] container: refactor entrypoint script
That entrypoint is prone to screw things up, especially with permission handling. The new script handles initialization better and fixes some issues like delayed settings update via ENVs and timestamp overwriting, also adjusts what should be copied into the container.

Related https://github.com/searxng/searxng/pull/4721#issuecomment-2850272129
2025-05-20 11:49:30 +02:00
Ivan Gabaldon
a195f52412 [fix] container: base-builder should have essentials
The wolfi-base metapackage includes busybox, ca-certificates-bundle and the package manager. The change is to make the use of base-builder image more flexible.
2025-05-20 11:31:45 +02:00
dependabot[bot]
5dff826937
[upd] web-client (simple): Bump vite-plugin-static-copy (#4791)
Bumps [vite-plugin-static-copy](https://github.com/sapphi-red/vite-plugin-static-copy) from 2.3.1 to 3.0.0.
- [Release notes](https://github.com/sapphi-red/vite-plugin-static-copy/releases)
- [Changelog](https://github.com/sapphi-red/vite-plugin-static-copy/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sapphi-red/vite-plugin-static-copy/compare/vite-plugin-static-copy@2.3.1...vite-plugin-static-copy@3.0.0)
2025-05-18 13:22:48 +02:00
Markus Heiser
b8b857d24c
[mod] engine invidious: commented out / no public API available nowadays (#4800)
Reported-by: @unifox https://github.com/searxng/searxng/issues/2722#issuecomment-2884993248

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-18 13:20:27 +02:00
Ivan Gabaldon
86373e7c87
[mod] container: build custom base images (#4799)
Instead of using Wolfi base images from cgr.dev and making that mess on the Dockerfile, why don't we build the base images ourselves from Wolfi repos with apko? The intention of this is to simplify the main Dockerfile and avoid having to patch the base image every time, it also simplifies some steps like image ownership management and provides extremely fast builds.
2025-05-17 18:21:04 +02:00
github-actions[bot]
1b08324f26
[l10n] update translations from Weblate (#4788) 2025-05-16 09:40:45 +02:00
dependabot[bot]
b8682ffc69
[upd] pypi: Bump typer-slim from 0.15.3 to 0.15.4 in the minor group (#4789)
Bumps the minor group with 1 update: [typer-slim](https://github.com/fastapi/typer).


Updates `typer-slim` from 0.15.3 to 0.15.4
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](https://github.com/fastapi/typer/compare/0.15.3...0.15.4)

---
updated-dependencies:
- dependency-name: typer-slim
  dependency-version: 0.15.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-16 09:20:44 +02:00
Ivan Gabaldon
03083f07da [enh] container: use Wolfi OS as base image
Wolfi OS images are specifically designed for container use. Using a specially designed base image for containers not only reduces maintenance burdens, but improves overall experience for developers (fewer packages we have to track) and end users (smaller images).

Discussion here: https://github.com/searxng/searxng/issues/4753
2025-05-15 22:56:31 +02:00
9f29131161 Merge pull request 'master' (#1) from Icycoide/searxng:master into master
Reviewed-on: #1
2025-05-15 22:35:22 +02:00
Ivan Gabaldon
cd64fb966e [enh] container: support multiple registries
Allows to push the manifests to other registries, this allows to push both docker.io and ghcr.io registries.
2025-05-15 11:37:18 +02:00
Ivan Gabaldon
743f24d8c6 [fix] CI: commit author should be searxng-bot
If the workflow is executed with the "workflow_dispatch" trigger, the user who executed the workflow becomes the author of the commit on the PR, this is not intended.

It also reverts the body param so that the default text of the action does not appear.
2025-05-15 11:19:28 +02:00
Ivan Gabaldon
bec76bc2e3 [fix] CI: prevent race condition
`checker.yml` and `integration.yml` are the only workflows that are currently safe to be executed simultaneously, the others present a risk that the order of completion may not be expected. The ones that are chained from `integration.yml` can be called as many times as `integration.yml` workflows are running at that moment, the same with the trigger "workflow_dispatch".

This can be fatal for workflows like `container.yml` that use a centralized cache to store and load the candidate images in a common tag called "searxng-<arch>".

* For example, a `container.yml` workflow is executed after being chained from `integration.yml` (called "~1"), and seconds later it may be triggered again because another PR merged some breaking changes (called "~2"). While "~1" has already passed the test job successfully and is about to start the release job, "~2" finishes building the container and overwrites the references on the common tag. When "~1" in the release job loads the images using the common tag, it will load the container of "~2" instead of "~1" having skipped the whole test job process.

The example is only set for the container workflow, but the other workflows might occur in a similar way.
2025-05-15 11:19:28 +02:00
Ivan Gabaldon
d0b7f26f4b [fix] CI: container-mounts bad hash
This is a typo, but if there are multiple patterns in hashFiles, they should be separated by commas.

https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions#examples-with-multiple-patterns
2025-05-15 11:19:28 +02:00
Ivan Gabaldon
b42f812c57
[fix] CI: handle old cache images from registry
Currently, we have 1100~ cache images uploaded to GHCR that weigh more than 300 MB each (most of them are layers from the second phase of the Dockerfile that were uploaded by mistake, read below). To avoid problems, I have set up a new job in a new workflow to be run weekly purging all images older than 1 week, but leaving always the 100 most recent ones.

Only the builder images should be uploaded to cache, the actual behaviour not only slows down the time for building the container, but also wastes lots of space by saving large and useless layers to GHCR that will never be used again.
2025-05-14 22:42:36 +02:00
dependabot[bot]
c73b469ce7
Bump flask from 3.1.0 to 3.1.1 (#4780)
Bumps [flask](https://github.com/pallets/flask) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/pallets/flask/releases)
- [Changelog](https://github.com/pallets/flask/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/flask/compare/3.1.0...3.1.1)
2025-05-14 08:18:03 +02:00
Ivan Gabaldon
1a8884fa26
[enh] tidy: clean old morty, filtron, searx references
Everyone should have already switched from legacy methods.
2025-05-13 21:10:02 +02:00
dependabot[bot]
4fb29aae81
[upd] pypi: Bump the minor group with 2 updates (#4776)
Bumps the minor group with 2 updates: [selenium](https://github.com/SeleniumHQ/Selenium) and [redis](https://github.com/redis/redis-py).


Updates `selenium` from 4.31.0 to 4.32.0
- [Release notes](https://github.com/SeleniumHQ/Selenium/releases)
- [Commits](https://github.com/SeleniumHQ/Selenium/compare/selenium-4.31.0...selenium-4.32.0)

Updates `redis` from 5.0.8 to 5.2.1
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/v5.0.8...v5.2.1)
2025-05-13 17:44:10 +02:00
dependabot[bot]
c303da55b0
[upd] web-client (simple): Bump the minor group (#4775)
Bumps the minor group in /client/simple with 5 updates:

| Package | From | To |
| --- | --- | --- |
| [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) | `9.25.1` | `9.26.0` |
| [eslint](https://github.com/eslint/eslint) | `9.25.1` | `9.26.0` |
| [globals](https://github.com/sindresorhus/globals) | `16.0.0` | `16.1.0` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `6.3.4` | `6.3.5` |
| [webpack](https://github.com/webpack/webpack) | `5.99.7` | `5.99.8` |


Updates `@eslint/js` from 9.25.1 to 9.26.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/commits/v9.26.0/packages/js)

Updates `eslint` from 9.25.1 to 9.26.0
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.25.1...v9.26.0)

Updates `globals` from 16.0.0 to 16.1.0
- [Release notes](https://github.com/sindresorhus/globals/releases)
- [Commits](https://github.com/sindresorhus/globals/compare/v16.0.0...v16.1.0)

Updates `vite` from 6.3.4 to 6.3.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.5/packages/vite)

Updates `webpack` from 5.99.7 to 5.99.8
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.99.7...v5.99.8)
2025-05-13 17:38:46 +02:00
Ivan Gabaldon
2cfd3fc44b
[enh] tidy: clean old morty, filtron, searx references
Everyone should have already switched from legacy methods
2025-05-13 10:37:02 +02:00
Markus Heiser
9006866019
[fix] engine archlinux: avoid Anubis challenge by User-Agent "SearXNG" (#4779)
Of the archlinux wikis only wiki.archlinux.org has a has Anubis challenge.

About Anubis[1]:

> Anubis decides to present a challenge using this logic:
>
> - User-Agent contains "Mozilla"
> ...
> This should ensure that git clients, RSS readers, and other low-harm clients
> can get through without issue ..

[1] 6c0ff3f4d5/docs/docs/design/how-anubis-works.mdx (challenge-presentation)


Suggested-by: @unixfox https://github.com/searxng/searxng/issues/4646#issuecomment-2855322406
Closes: https://github.com/searxng/searxng/issues/4646

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-13 10:18:28 +02:00
Ivan Gabaldon
5d99373bc6
[fix] DOCKERHUB_USERNAME env reference (#4778)
When making the container rework, I unknowingly deleted the section where an env with the same name as the secret was defined on the job scope, making it look like it was originally defined as an organization env.

Since we can't validate the secrets in a condition directly, it's better to let docker/login-action take care of failing the entire job if the credentials are invalid.

Reported in: https://github.com/searxng/searxng/issues/4777
2025-05-12 23:43:47 +02:00
Ivan Gabaldon
945b30a1c4 [mod] lib_sxng_container.sh: replace echo commands with heredoc
Suggested-by: @return42 https://github.com/searxng/searxng/pull/4764#discussion_r2083571202
2025-05-12 17:11:35 +02:00
Ivan Gabaldon
64a5b6920f [mod] lib_sxng_container.sh use required_commands() helper
Suggested-by: @return42 https://github.com/searxng/searxng/pull/4764#discussion_r2083564489
2025-05-12 17:11:35 +02:00
Markus Heiser
346d7fe019
[mod] CI: dependabot group updates by minor & patch and major updates (#4773)
By default, Dependabot opens a new pull request to update each dependency and we
have a very large number of Dependabot pull requests to review and merge, which
can quickly become difficult to manage.

The intention of this patch to dependabot is to have:

- one PR for all minor & patch level updates
- one PR for every dependency with a major update

[1] https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates
[2] https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#groups

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-12 16:42:43 +02:00
Markus Heiser
750a7b4d6f
[doc] add chapter on the purpose of (git) commits (#4729)
Chapter on the purpose of (git) commits

The commits and their messages are elementary for the traceability of changes
and are unfortunately still too often given too little attention.

It therefore seems necessary to dedicate a chapter to this topic in the context
of development.

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-12 08:27:16 +02:00
Ivan Gabaldon
da3c640cef revert using null keyword
env.DOCKERHUB_USERNAME shouldn't be an empty string as it's defined and set (I think, I can't see this). Even if wasn't defined, GitHub Org/Repo wide envs/secrets should return an empty string (?)
2025-05-11 19:28:51 +02:00
Ivan Gabaldon
d16854e67a
[mod] rework container deployment (#4764)
container.yml will run after integration.yml COMPLETES successfully and in master branch.

Style changes, cleanup and improved integration with CI by leveraging the use of
shared cache between all workflows.

* Podman is now supported to build the container images (Docker also received a refactor, merging both build and buildx)
* Container images are being built by Buildah instead of Docker BuildKit.
* Container images are tested before release.
* Splitting "modern" (amd64 & arm64) and "legacy" (armv7) arches on different Dockerfiles allowing future optimizations.
2025-05-11 18:12:51 +02:00
Ivan Gabaldon
1b787ed35e
[mod] refactor integration.yml (#4763)
Style changes, cleanup and improved integration with CI by leveraging the use of
shared cache between all workflows.
2025-05-10 13:59:31 +02:00
Ivan Gabaldon
8e2e7774d7
[mod] new l10n.yml workflow (#4734)
l10n.yml will run after integration.yml finishes successfully (will defer anything depending on integration.yml until heavy loads like container building are moved to separate workflows) and in master branch.

* After every integration.yml workflow completes successfully, only the `update` job runs.
* Dispatch and Crontab triggers only the `pr` job.

Style changes, cleanup and improved integration with CI by leveraging the use of shared cache between all workflows (not functional until all workflows have been refactored).
2025-05-10 13:08:20 +02:00
Ivan Gabaldon
e982b9f732 [fix] documentation should run on push/pr
Instead of executing the workflow after integration.yml completes correctly, let's run this workflow parallel to integration.yml restoring the original behaviour.
2025-05-10 07:41:42 +02:00
Émilien (perso)
48456caeb3
chore: docker + github-actions dependabot (#4754)
* chore: docker dependabot

* Add github actions too
2025-05-09 20:46:20 +02:00
kevadesu
df9d418222 Fixing branding 2025-05-09 18:05:13 +02:00
kevadesu
d456f13f2e Editing branding again 2025-05-09 18:00:19 +02:00
kevadesu
77b78fab04 Branding 2025-05-09 17:39:56 +02:00
Markus Heiser
ef158ce1f4 [build] /static 2025-05-09 12:40:34 +02:00
Markus Heiser
cbf9ec7bf4 [fix] static.build.commit: add missing searx/templates/simple/icons.html
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-09 12:40:34 +02:00
Markus Heiser
409ede1530 [fix] simple client: jinja_svg_catalog addClassesToSVGElement
Starting with ionicons-8.0.8 the SVG already contains a class attribute and
instaed of using SVGO plugin ``addAttributesToSVGElement`` we habve to use
``addClassesToSVGElement`` to add out ``__jinja_class_placeholder__``.

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2025-05-09 12:40:34 +02:00
dependabot[bot]
1326ec7429 [upd] web-client (simple): Bump ionicons in /client/simple
Bumps [ionicons](https://github.com/ionic-team/ionicons) from 7.4.0 to 8.0.8.
- [Release notes](https://github.com/ionic-team/ionicons/releases)
- [Commits](https://github.com/ionic-team/ionicons/compare/v7.4.0...v8.0.8)

---
updated-dependencies:
- dependency-name: ionicons
  dependency-version: 8.0.8
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-05-09 12:40:34 +02:00
dependabot[bot]
50406d4b46
[upd] pypi: Bump pylint from 3.3.6 to 3.3.7 (#4750)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.3.6 to 3.3.7.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.3.6...v3.3.7)

---
updated-dependencies:
- dependency-name: pylint
  dependency-version: 3.3.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 11:10:37 +02:00
dependabot[bot]
5ce3aa3acf
[upd] pypi: Bump yamllint from 1.37.0 to 1.37.1 (#4752)
Bumps [yamllint](https://github.com/adrienverge/yamllint) from 1.37.0 to 1.37.1.
- [Release notes](https://github.com/adrienverge/yamllint/releases)
- [Changelog](https://github.com/adrienverge/yamllint/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/adrienverge/yamllint/compare/v1.37.0...v1.37.1)

---
updated-dependencies:
- dependency-name: yamllint
  dependency-version: 1.37.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 11:09:44 +02:00
SearXNG Bot
76ebad0b21
[l10n] update translations from Weblate (#4744)
6f8c520f2 - 2025-05-08 - polskiecus <polskiecus@noreply.codeberg.org>
05dd91d5b - 2025-05-08 - return42 <return42@noreply.codeberg.org>
686b8e5fb - 2025-05-08 - return42 <return42@noreply.codeberg.org>
f40b42bd8 - 2025-05-05 - ehsanrs2 <ehsanrs2@noreply.codeberg.org>
b8013bc99 - 2025-05-03 - polskiecus <polskiecus@noreply.codeberg.org>
5affaa104 - 2025-05-02 - SomeTr <sometr@noreply.codeberg.org>

Co-authored-by: searxng-bot <searxng-bot@users.noreply.github.com>
2025-05-09 09:31:50 +02:00
github-actions[bot]
d76f030cb3
[data] update searx.data - update_wikidata_units.py (#4738) 2025-05-09 07:09:58 +02:00
github-actions[bot]
b3b15ecc72
[data] update searx.data - update_ahmia_blacklist.py (#4739)
Co-authored-by: inetol <inetol@users.noreply.github.com>
2025-05-09 07:09:00 +02:00
github-actions[bot]
1319b250af
[data] update searx.data - update_currencies.py (#4740)
Co-authored-by: inetol <inetol@users.noreply.github.com>
2025-05-09 07:08:26 +02:00
github-actions[bot]
198928de05
[data] update searx.data - update_engine_traits.py (#4741)
Co-authored-by: inetol <inetol@users.noreply.github.com>
2025-05-09 07:07:33 +02:00
github-actions[bot]
11d9c830b8
[data] update searx.data - update_engine_descriptions.py (#4742)
Co-authored-by: inetol <inetol@users.noreply.github.com>
2025-05-09 07:06:52 +02:00
230 changed files with 5568 additions and 3964 deletions

View file

@ -10,6 +10,12 @@ updates:
target-branch: "master"
commit-message:
prefix: "[upd] pypi:"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "npm"
directory: "/client/simple"
@ -20,3 +26,27 @@ updates:
target-branch: "master"
commit-message:
prefix: "[upd] web-client (simple):"
groups:
minor:
applies-to: version-updates
update-types:
- "minor"
- "patch"
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
target-branch: "master"
commit-message:
prefix: "[upd] docker:"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
day: "friday"
target-branch: "master"
commit-message:
prefix: "[upd] github-actions:"

View file

@ -8,7 +8,7 @@ on:
- cron: "0 4 * * 5"
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:

36
.github/workflows/cleanup.yml vendored Normal file
View file

@ -0,0 +1,36 @@
---
name: Cleanup
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
schedule:
- cron: "4 4 * * *"
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
contents: read
jobs:
container-cache:
# FIXME: On forks it fails with "Failed to fetch packages: missing field `id` at line 1 column 141"
if: github.repository_owner == 'searxng' || github.event_name == 'workflow_dispatch'
name: Container cache
runs-on: ubuntu-24.04
permissions:
# Organization GHCR
packages: write
steps:
- name: Prune
uses: snok/container-retention-policy@v3.0.0
with:
account: "${{ github.repository_owner }}"
token: "${{ secrets.GITHUB_TOKEN }}"
image-names: "cache base"
image-tags: "!searxng*"
cut-off: "1d"
keep-n-most-recent: "100"

252
.github/workflows/container.yml vendored Normal file
View file

@ -0,0 +1,252 @@
---
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
# Organization GHCR
packages: read
env:
PYTHON_VERSION: "3.13"
jobs:
build-base:
if: |
(github.repository_owner == 'searxng' && github.event.workflow_run.conclusion == 'success')
|| github.event_name == 'workflow_dispatch'
name: Build base
runs-on: ubuntu-24.04
permissions:
# Organization GHCR
packages: write
steps:
- if: github.repository_owner == 'searxng'
name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- if: github.repository_owner == 'searxng'
name: Get date
id: date
run: echo "date=$(date +'%Y%m%d')" >>$GITHUB_OUTPUT
- if: github.repository_owner == 'searxng'
name: Check cache apko
id: cache-apko
uses: actions/cache/restore@v4
with:
# yamllint disable-line rule:line-length
key: "apko-${{ steps.date.outputs.date }}-${{ hashFiles('./container/base.yml', './container/base-builder.yml') }}"
path: "/tmp/.apko/"
lookup-only: true
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Setup cache apko
uses: actions/cache@v4
with:
# yamllint disable-line rule:line-length
key: "apko-${{ steps.date.outputs.date }}-${{ hashFiles('./container/base.yml', './container/base-builder.yml') }}"
restore-keys: "apko-${{ steps.date.outputs.date }}-"
path: "/tmp/.apko/"
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Setup apko
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
brew install apko
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Login to GHCR
uses: docker/login-action@v3
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Build
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
apko publish ./container/base.yml ghcr.io/${{ github.repository_owner }}/base:searxng \
--cache-dir=/tmp/.apko/ \
--sbom=false \
--vcs=false \
--log-level=debug
apko publish ./container/base-builder.yml ghcr.io/${{ github.repository_owner }}/base:searxng-builder \
--cache-dir=/tmp/.apko/ \
--sbom=false \
--vcs=false \
--log-level=debug
build:
if: github.repository_owner == 'searxng' || github.event_name == 'workflow_dispatch'
name: Build (${{ matrix.arch }})
runs-on: ${{ matrix.os }}
needs: build-base
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
permissions:
# Organization GHCR
packages: write
outputs:
version_string: ${{ steps.build.outputs.version_string }}
version_tag: ${{ steps.build.outputs.version_tag }}
docker_tag: ${{ steps.build.outputs.docker_tag }}
git_url: ${{ steps.build.outputs.git_url }}
git_branch: ${{ steps.build.outputs.git_branch }}
steps:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- name: Setup cache Python
uses: actions/cache@v4
with:
key: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-${{ hashFiles('./requirements*.txt') }}"
restore-keys: "python-${{ env.PYTHON_VERSION }}-${{ runner.arch }}-"
path: "./local/"
- name: Setup cache container mounts
uses: actions/cache@v4
with:
# yamllint disable-line rule:line-length
key: "container-mounts-${{ matrix.arch }}-${{ hashFiles('./container/Dockerfile', './container/legacy/Dockerfile') }}"
restore-keys: "container-mounts-${{ matrix.arch }}-"
path: |
/var/tmp/buildah-cache/
/var/tmp/buildah-cache-*/
- if: ${{ matrix.emulation }}
name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
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@v4
with:
persist-credentials: "false"
- if: ${{ matrix.emulation }}
name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Login to GHCR
uses: docker/login-action@v3
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 == 'searxng' && github.ref_name == 'master'
name: Release
runs-on: ubuntu-24.04-arm
needs:
- build
- test
permissions:
# Organization GHCR
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
registry: "docker.io"
username: "${{ secrets.DOCKERHUB_USERNAME }}"
password: "${{ secrets.DOCKERHUB_TOKEN }}"
- name: Release
env:
GIT_URL: "${{ needs.build.outputs.git_url }}"
DOCKER_TAG: "${{ needs.build.outputs.docker_tag }}"
run: make container.push

View file

@ -8,7 +8,7 @@ on:
- cron: "59 23 28 * *"
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
@ -66,7 +66,7 @@ jobs:
id: cpr
uses: peter-evans/create-pull-request@v7
with:
author: "${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>"
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 }}"
@ -74,6 +74,8 @@ jobs:
delete-branch: "true"
draft: "false"
signoff: "false"
body: |
[data] update searx.data - ${{ matrix.fetch }}
labels: |
data

View file

@ -4,16 +4,15 @@ name: Documentation
# yamllint disable-line rule:truthy
on:
workflow_dispatch:
workflow_run:
workflows:
- Integration
types:
- completed
push:
branches:
- master
pull_request:
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
@ -24,7 +23,6 @@ env:
jobs:
release:
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
name: Release
runs-on: ubuntu-24.04-arm
permissions:
@ -56,7 +54,8 @@ jobs:
- name: Build documentation
run: make V=1 docs.clean docs.html
- name: Release
- if: github.ref_name == 'master'
name: Release
uses: JamesIves/github-pages-deploy-action@v4
with:
folder: "dist/docs"

View file

@ -1,136 +1,96 @@
---
name: Integration
on: # yamllint disable-line rule:truthy
# yamllint disable-line rule:truthy
on:
push:
branches: ["master"]
branches:
- master
pull_request:
branches: ["master"]
branches:
- master
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: false
permissions:
contents: read
env:
PYTHON_VERSION: "3.13"
jobs:
python:
test:
name: Python ${{ matrix.python-version }}
runs-on: ubuntu-24.04
strategy:
matrix:
os: [ubuntu-24.04]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
python-version:
- "3.9"
- "3.10"
- "3.11"
- "3.12"
- "3.13"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Ubuntu packages
run: |
sudo ./utils/searxng.sh install packages
- name: Set up Python
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
architecture: 'x64'
python-version: "${{ matrix.python-version }}"
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- name: Setup cache Python
uses: actions/cache@v4
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
themes:
name: Themes
runs-on: ubuntu-24.04
theme:
name: Theme
runs-on: ubuntu-24.04-arm
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Ubuntu packages
run: sudo ./utils/searxng.sh install buildhost
- name: Set up Python
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
architecture: 'x64'
- name: Build themes
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version-file: "./.nvmrc"
- name: Setup cache Node.js
uses: actions/cache@v4
with:
key: "nodejs-${{ runner.arch }}-${{ hashFiles('./.nvmrc', './package.json') }}"
path: "./client/simple/node_modules/"
- name: Setup cache Python
uses: actions/cache@v4
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
run: make themes.all
babel:
name: Update translations branch
runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'searxng' && github.ref == 'refs/heads/master' }}
needs:
- python
- themes
permissions:
contents: write # for make V=1 weblate.push.translations
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: '0'
token: ${{ secrets.WEBLATE_GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
architecture: 'x64'
- name: Cache Python dependencies
id: cache-python
uses: actions/cache@v4
with:
path: |
./local
./.nvm
./node_modules
key: python-ubuntu-20.04-3.12-${{ hashFiles('requirements*.txt', 'setup.py','.nvmrc', 'package.json') }}
- name: weblate & git setup
env:
WEBLATE_CONFIG: ${{ secrets.WEBLATE_CONFIG }}
run: |
mkdir -p ~/.config
echo "${WEBLATE_CONFIG}" > ~/.config/weblate
git config --global user.email "searxng-bot@users.noreply.github.com"
git config --global user.name "searxng-bot"
- name: Update transations
id: update
run: |
make V=1 weblate.push.translations
dockers:
name: Docker
if: github.ref == 'refs/heads/master'
needs:
- python
- themes
env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
runs-on: ubuntu-24.04
steps:
- name: Checkout
if: env.DOCKERHUB_USERNAME != null
uses: actions/checkout@v4
with:
# make sure "make docker.push" can get the git history
fetch-depth: '0'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
architecture: 'x64'
- name: Cache Python dependencies
id: cache-python
uses: actions/cache@v4
with:
path: |
./local
./.nvm
./node_modules
key: python-ubuntu-20.04-3.12-${{ hashFiles('requirements*.txt', 'setup.py','.nvmrc', 'package.json') }}
- name: Set up QEMU
if: env.DOCKERHUB_USERNAME != null
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
if: env.DOCKERHUB_USERNAME != null
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
if: env.DOCKERHUB_USERNAME != null
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
if: env.DOCKERHUB_USERNAME != null
run: make -e GIT_URL=$(git remote get-url origin) docker.buildx

138
.github/workflows/l10n.yml vendored Normal file
View file

@ -0,0 +1,138 @@
---
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.13"
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@v5
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@v4
with:
token: "${{ secrets.WEBLATE_GITHUB_TOKEN }}"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@v4
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@v5
with:
python-version: "${{ env.PYTHON_VERSION }}"
- name: Checkout
uses: actions/checkout@v4
with:
token: "${{ secrets.WEBLATE_GITHUB_TOKEN }}"
fetch-depth: "0"
- name: Setup cache Python
uses: actions/cache@v4
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@v7
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: |
translation
- name: Display information
run: |
echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"

View file

@ -8,7 +8,7 @@ on:
- cron: "42 05 * * *"
concurrency:
group: ${{ github.workflow }}-${{ github.ref_name }}
group: ${{ github.workflow }}
cancel-in-progress: false
permissions:
@ -16,6 +16,7 @@ permissions:
jobs:
container:
if: github.repository_owner == 'searxng'
name: Container
runs-on: ubuntu-24.04-arm
permissions:
@ -30,7 +31,7 @@ jobs:
- name: Run Trivy scanner
uses: aquasecurity/trivy-action@0.30.0
with:
image-ref: "docker.io/searxng/searxng:latest"
image-ref: "ghcr.io/searxng/searxng:latest"
vuln-type: "os,library"
severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
ignore-unfixed: "false"

View file

@ -1,59 +0,0 @@
name: "Update translations"
on: # yamllint disable-line rule:truthy
schedule:
- cron: "05 07 * * 5"
workflow_dispatch:
jobs:
babel:
name: "create PR for additions from weblate"
runs-on: ubuntu-24.04
if: ${{ github.repository_owner == 'searxng' && github.ref == 'refs/heads/master' }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: '0'
token: ${{ secrets.WEBLATE_GITHUB_TOKEN }}
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
architecture: 'x64'
- name: Cache Python dependencies
id: cache-python
uses: actions/cache@v4
with:
path: |
./local
./.nvm
./node_modules
key: python-ubuntu-24.04-3.12-${{ hashFiles('requirements*.txt', 'setup.py','.nvmrc', 'package.json') }}
- name: weblate & git setup
env:
WEBLATE_CONFIG: ${{ secrets.WEBLATE_CONFIG }}
run: |
mkdir -p ~/.config
echo "${WEBLATE_CONFIG}" > ~/.config/weblate
git config --global user.email "searxng-bot@users.noreply.github.com"
git config --global user.name "searxng-bot"
- name: Merge and push transation updates
run: |
make V=1 weblate.translations.commit
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v3
with:
token: ${{ secrets.WEBLATE_GITHUB_TOKEN }}
commit-message: '[l10n] update translations from Weblate'
committer: searxng-bot <searxng-bot@users.noreply.github.com>
author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com>
signoff: false
branch: translations_update
delete-branch: true
draft: false
title: '[l10n] update translations from Weblate'
body: |
update translations from Weblate
labels: |
translation

View file

@ -54,7 +54,7 @@ ci.test: test.yamllint test.black test.types.ci test.pylint test.unit test.robo
test: test.yamllint test.black test.types.dev test.pylint test.unit test.robot test.rst test.shell
test.shell:
$(Q)shellcheck -x -s dash \
dockerfiles/docker-entrypoint.sh
container/entrypoint.sh
$(Q)shellcheck -x -s bash \
utils/brand.sh \
$(MTOOLS) \
@ -65,10 +65,7 @@ test.shell:
utils/lib_redis.sh \
utils/searxng.sh \
utils/lxc.sh \
utils/lxc-searxng.env \
utils/searx.sh \
utils/filtron.sh \
utils/morty.sh
utils/lxc-searxng.env
$(Q)$(MTOOLS) build_msg TEST "$@ OK"
@ -77,7 +74,9 @@ test.shell:
MANAGE += weblate.translations.commit weblate.push.translations
MANAGE += data.all data.traits data.useragents data.locales data.currencies
MANAGE += docs.html docs.live docs.gh-pages docs.prebuild docs.clean
MANAGE += docker.build docker.push docker.buildx
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
@ -95,8 +94,8 @@ $(MANAGE):
# short hands of selected targets
PHONY += docs docker themes
PHONY += docs container themes
docs: docs.html
docker: docker.build
container: container.build
themes: themes.all

View file

@ -10,6 +10,8 @@
----
Fork of SearXNG. The globe icon for empty_favicon.svg in searx/static/themes/simple/img/ belongs to the Noto Emojis font by Google
Privacy-respecting, hackable `metasearch engine`_
Searx.space_ lists ready-to-use running instances.

View file

@ -7,34 +7,31 @@
"": {
"name": "simple",
"version": "1.0.0",
"dependencies": {
"autocomplete-js": "^2.7.1"
},
"devDependencies": {
"@eslint/js": "^9.25.1",
"@eslint/js": "^9.27.0",
"copy-webpack-plugin": "^13.0.0",
"css-loader": "^7.1.2",
"edge.js": "^6.2.1",
"eslint": "^9.25.1",
"eslint": "^9.27.0",
"filemanager-webpack-plugin": "^8.0.0",
"globals": "^16.0.0",
"ionicons": "^7.4.0",
"globals": "^16.2.0",
"ionicons": "^8.0.8",
"leaflet": "^1.9.4",
"less": "^4.3.0",
"less-loader": "^12.3.0",
"normalize.css": "^8.0.1",
"sharp": "^0.34.1",
"sharp": "^0.34.2",
"style-loader": "^4.0.0",
"stylelint": "^16.19.1",
"stylelint": "^16.20.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-config-standard-less": "^3.0.1",
"stylelint-prettier": "^5.0.3",
"svgo": "^3.3.2",
"swiped-events": "^1.2.0",
"vite": "^6.3.4",
"vite-plugin-static-copy": "^2.3.1",
"vite": "^6.3.5",
"vite-plugin-static-copy": "^3.0.0",
"vite-plugin-stylelint": "^6.0.0",
"webpack": "^5.99.7",
"webpack": "^5.99.9",
"webpack-cli": "^6.0.1"
}
},
@ -175,9 +172,9 @@
}
},
"node_modules/@emnapi/runtime": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.0.tgz",
"integrity": "sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz",
"integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==",
"dev": true,
"license": "MIT",
"optional": true,
@ -678,9 +675,9 @@
}
},
"node_modules/@eslint/core": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz",
"integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==",
"version": "0.14.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz",
"integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@ -728,13 +725,16 @@
}
},
"node_modules/@eslint/js": {
"version": "9.25.1",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz",
"integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==",
"version": "9.27.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz",
"integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://eslint.org/donate"
}
},
"node_modules/@eslint/object-schema": {
@ -748,13 +748,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz",
"integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz",
"integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.13.0",
"@eslint/core": "^0.14.0",
"levn": "^0.4.1"
},
"engines": {
@ -828,9 +828,9 @@
}
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz",
"integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz",
"integrity": "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==",
"cpu": [
"arm64"
],
@ -851,9 +851,9 @@
}
},
"node_modules/@img/sharp-darwin-x64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz",
"integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz",
"integrity": "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==",
"cpu": [
"x64"
],
@ -1027,9 +1027,9 @@
}
},
"node_modules/@img/sharp-linux-arm": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz",
"integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz",
"integrity": "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==",
"cpu": [
"arm"
],
@ -1050,9 +1050,9 @@
}
},
"node_modules/@img/sharp-linux-arm64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz",
"integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz",
"integrity": "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==",
"cpu": [
"arm64"
],
@ -1073,9 +1073,9 @@
}
},
"node_modules/@img/sharp-linux-s390x": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz",
"integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz",
"integrity": "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==",
"cpu": [
"s390x"
],
@ -1096,9 +1096,9 @@
}
},
"node_modules/@img/sharp-linux-x64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz",
"integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz",
"integrity": "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==",
"cpu": [
"x64"
],
@ -1119,9 +1119,9 @@
}
},
"node_modules/@img/sharp-linuxmusl-arm64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz",
"integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz",
"integrity": "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==",
"cpu": [
"arm64"
],
@ -1142,9 +1142,9 @@
}
},
"node_modules/@img/sharp-linuxmusl-x64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz",
"integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz",
"integrity": "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==",
"cpu": [
"x64"
],
@ -1165,9 +1165,9 @@
}
},
"node_modules/@img/sharp-wasm32": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz",
"integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz",
"integrity": "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==",
"cpu": [
"wasm32"
],
@ -1175,7 +1175,7 @@
"license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
"optional": true,
"dependencies": {
"@emnapi/runtime": "^1.4.0"
"@emnapi/runtime": "^1.4.3"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@ -1184,10 +1184,30 @@
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-arm64": {
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz",
"integrity": "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "Apache-2.0 AND LGPL-3.0-or-later",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/@img/sharp-win32-ia32": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz",
"integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz",
"integrity": "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==",
"cpu": [
"ia32"
],
@ -1205,9 +1225,9 @@
}
},
"node_modules/@img/sharp-win32-x64": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz",
"integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz",
"integrity": "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==",
"cpu": [
"x64"
],
@ -1766,9 +1786,9 @@
]
},
"node_modules/@stencil/core": {
"version": "4.26.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.26.0.tgz",
"integrity": "sha512-+0Inu+dJ9/LgWSskcZwx7v17v4GILcwIYxNgD+OuK0U+D5z61WsxWw7yHkYG5OqGPBijsJMVssYRx/Tn+e7F9A==",
"version": "4.31.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.31.0.tgz",
"integrity": "sha512-Ei9MFJ6LPD9BMFs+klkHylbVOOYhG10Jv4bvoFf3GMH15kA41rSYkEdr4DiX84ZdErQE2qtFV/2SUyWoXh0AhA==",
"dev": true,
"license": "MIT",
"bin": {
@ -1777,8 +1797,130 @@
"engines": {
"node": ">=16.0.0",
"npm": ">=7.10.0"
},
"optionalDependencies": {
"@rollup/rollup-darwin-arm64": "4.34.9",
"@rollup/rollup-darwin-x64": "4.34.9",
"@rollup/rollup-linux-arm64-gnu": "4.34.9",
"@rollup/rollup-linux-arm64-musl": "4.34.9",
"@rollup/rollup-linux-x64-gnu": "4.34.9",
"@rollup/rollup-linux-x64-musl": "4.34.9",
"@rollup/rollup-win32-arm64-msvc": "4.34.9",
"@rollup/rollup-win32-x64-msvc": "4.34.9"
}
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.9.tgz",
"integrity": "sha512-0CY3/K54slrzLDjOA7TOjN1NuLKERBgk9nY5V34mhmuu673YNb+7ghaDUs6N0ujXR7fz5XaS5Aa6d2TNxZd0OQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-darwin-x64": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.9.tgz",
"integrity": "sha512-eOojSEAi/acnsJVYRxnMkPFqcxSMFfrw7r2iD9Q32SGkb/Q9FpUY1UlAu1DH9T7j++gZ0lHjnm4OyH2vCI7l7Q==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.9.tgz",
"integrity": "sha512-6TZjPHjKZUQKmVKMUowF3ewHxctrRR09eYyvT5eFv8w/fXarEra83A2mHTVJLA5xU91aCNOUnM+DWFMSbQ0Nxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.9.tgz",
"integrity": "sha512-LD2fytxZJZ6xzOKnMbIpgzFOuIKlxVOpiMAXawsAZ2mHBPEYOnLRK5TTEsID6z4eM23DuO88X0Tq1mErHMVq0A==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.9.tgz",
"integrity": "sha512-FwBHNSOjUTQLP4MG7y6rR6qbGw4MFeQnIBrMe161QGaQoBQLqSUEKlHIiVgF3g/mb3lxlxzJOpIBhaP+C+KP2A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.9.tgz",
"integrity": "sha512-cYRpV4650z2I3/s6+5/LONkjIz8MBeqrk+vPXV10ORBnshpn8S32bPqQ2Utv39jCiDcO2eJTuSlPXpnvmaIgRA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.9.tgz",
"integrity": "sha512-z4mQK9dAN6byRA/vsSgQiPeuO63wdiDxZ9yg9iyX2QTzKuQM7T4xlBoeUP/J8uiFkqxkcWndWi+W7bXdPbt27Q==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@stencil/core/node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.34.9",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.9.tgz",
"integrity": "sha512-AyleYRPU7+rgkMWbEh71fQlrzRfeP6SyMnRf9XX4fCdDPAJumdSBqYEcWPMzVQ4ScAl7E4oFfK0GUVn77xSwbw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@ -2345,12 +2487,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/autocomplete-js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/autocomplete-js/-/autocomplete-js-2.7.1.tgz",
"integrity": "sha512-F+1Sj13zbfpbkprKjtyYiaHgBo6YODzNzWgJjgo/p312AeiZVEn3W+NaRRzVZYqMI0Bm7/W36uanp995eNDy+A==",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -2521,14 +2657,14 @@
}
},
"node_modules/cacheable": {
"version": "1.8.10",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.8.10.tgz",
"integrity": "sha512-0ZnbicB/N2R6uziva8l6O6BieBklArWyiGx4GkwAhLKhSHyQtRfM9T1nx7HHuHDKkYB/efJQhz3QJ6x/YqoZzA==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/cacheable/-/cacheable-1.9.0.tgz",
"integrity": "sha512-8D5htMCxPDUULux9gFzv30f04Xo3wCnik0oOxKoRTPIBoqA7HtOcJ87uBhQTs3jCfZZTrUBGsYIZOgE0ZRgMAg==",
"dev": true,
"license": "MIT",
"dependencies": {
"hookified": "^1.8.1",
"keyv": "^5.3.2"
"hookified": "^1.8.2",
"keyv": "^5.3.3"
}
},
"node_modules/cacheable/node_modules/keyv": {
@ -3040,9 +3176,9 @@
"license": "CC0-1.0"
},
"node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3109,9 +3245,9 @@
}
},
"node_modules/detect-libc": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"dev": true,
"license": "Apache-2.0",
"engines": {
@ -3454,9 +3590,9 @@
}
},
"node_modules/eslint": {
"version": "9.25.1",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz",
"integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==",
"version": "9.27.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.27.0.tgz",
"integrity": "sha512-ixRawFQuMB9DZ7fjU3iGGganFDp3+45bPOdaRurcFHSXO1e/sYwUX/FtQZpLZJR6SjMoJH8hR2pPEAfDyCoU2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -3464,10 +3600,10 @@
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.20.0",
"@eslint/config-helpers": "^0.2.1",
"@eslint/core": "^0.13.0",
"@eslint/core": "^0.14.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.25.1",
"@eslint/plugin-kit": "^0.2.8",
"@eslint/js": "9.27.0",
"@eslint/plugin-kit": "^0.3.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@ -3972,9 +4108,9 @@
}
},
"node_modules/globals": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz",
"integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==",
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
"integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
"dev": true,
"license": "MIT",
"engines": {
@ -4032,9 +4168,9 @@
}
},
"node_modules/hookified": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/hookified/-/hookified-1.8.2.tgz",
"integrity": "sha512-5nZbBNP44sFCDjSoB//0N7m508APCgbQ4mGGo1KJGBYyCKNHfry1Pvd0JVHZIxjdnqn8nFRBAN/eFB6Rk/4w5w==",
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/hookified/-/hookified-1.9.0.tgz",
"integrity": "sha512-2yEEGqphImtKIe1NXWEhu6yD3hlFR4Mxk4Mtp3XEyScpSt4pQ4ymmXA1zzxZpj99QkFK+nN0nzjeb2+RUi/6CQ==",
"dev": true,
"license": "MIT"
},
@ -4217,13 +4353,13 @@
}
},
"node_modules/ionicons": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.4.0.tgz",
"integrity": "sha512-ZK94MMqgzMCPPMhmk8Ouu6goyVHFIlw/ACP6oe3FrikcI0N7CX0xcwVaEbUc0G/v3W0shI93vo+9ve/KpvcNhQ==",
"version": "8.0.8",
"resolved": "https://registry.npmjs.org/ionicons/-/ionicons-8.0.8.tgz",
"integrity": "sha512-CRHhDQA5vsNxC7raeEPqddgO90iR2F13VZS7hB0Vx7JrxJMM2060E3ddgYbpMQNJjzeBsgpkNwdBeK5qQ7RbLA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@stencil/core": "^4.0.3"
"@stencil/core": "^4.30.0"
}
},
"node_modules/is-arrayish": {
@ -5822,9 +5958,9 @@
"license": "BSD-3-Clause"
},
"node_modules/semver": {
"version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"dev": true,
"license": "ISC",
"bin": {
@ -5858,16 +5994,16 @@
}
},
"node_modules/sharp": {
"version": "0.34.1",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz",
"integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==",
"version": "0.34.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.2.tgz",
"integrity": "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==",
"dev": true,
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
"color": "^4.2.3",
"detect-libc": "^2.0.3",
"semver": "^7.7.1"
"detect-libc": "^2.0.4",
"semver": "^7.7.2"
},
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
@ -5876,8 +6012,8 @@
"url": "https://opencollective.com/libvips"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "0.34.1",
"@img/sharp-darwin-x64": "0.34.1",
"@img/sharp-darwin-arm64": "0.34.2",
"@img/sharp-darwin-x64": "0.34.2",
"@img/sharp-libvips-darwin-arm64": "1.1.0",
"@img/sharp-libvips-darwin-x64": "1.1.0",
"@img/sharp-libvips-linux-arm": "1.1.0",
@ -5887,15 +6023,16 @@
"@img/sharp-libvips-linux-x64": "1.1.0",
"@img/sharp-libvips-linuxmusl-arm64": "1.1.0",
"@img/sharp-libvips-linuxmusl-x64": "1.1.0",
"@img/sharp-linux-arm": "0.34.1",
"@img/sharp-linux-arm64": "0.34.1",
"@img/sharp-linux-s390x": "0.34.1",
"@img/sharp-linux-x64": "0.34.1",
"@img/sharp-linuxmusl-arm64": "0.34.1",
"@img/sharp-linuxmusl-x64": "0.34.1",
"@img/sharp-wasm32": "0.34.1",
"@img/sharp-win32-ia32": "0.34.1",
"@img/sharp-win32-x64": "0.34.1"
"@img/sharp-linux-arm": "0.34.2",
"@img/sharp-linux-arm64": "0.34.2",
"@img/sharp-linux-s390x": "0.34.2",
"@img/sharp-linux-x64": "0.34.2",
"@img/sharp-linuxmusl-arm64": "0.34.2",
"@img/sharp-linuxmusl-x64": "0.34.2",
"@img/sharp-wasm32": "0.34.2",
"@img/sharp-win32-arm64": "0.34.2",
"@img/sharp-win32-ia32": "0.34.2",
"@img/sharp-win32-x64": "0.34.2"
}
},
"node_modules/shebang-command": {
@ -6098,9 +6235,9 @@
}
},
"node_modules/stylelint": {
"version": "16.19.1",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.19.1.tgz",
"integrity": "sha512-C1SlPZNMKl+d/C867ZdCRthrS+6KuZ3AoGW113RZCOL0M8xOGpgx7G70wq7lFvqvm4dcfdGFVLB/mNaLFChRKw==",
"version": "16.20.0",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.20.0.tgz",
"integrity": "sha512-B5Myu9WRxrgKuLs3YyUXLP2H0mrbejwNxPmyADlACWwFsrL8Bmor/nTSh4OMae5sHjOz6gkSeccQH34gM4/nAw==",
"dev": true,
"funding": [
{
@ -6124,15 +6261,15 @@
"cosmiconfig": "^9.0.0",
"css-functions-list": "^3.2.3",
"css-tree": "^3.1.0",
"debug": "^4.3.7",
"debug": "^4.4.1",
"fast-glob": "^3.3.3",
"fastest-levenshtein": "^1.0.16",
"file-entry-cache": "^10.0.8",
"file-entry-cache": "^10.1.0",
"global-modules": "^2.0.0",
"globby": "^11.1.0",
"globjoin": "^0.1.4",
"html-tags": "^3.3.1",
"ignore": "^7.0.3",
"ignore": "^7.0.4",
"imurmurhash": "^0.1.4",
"is-plain-object": "^5.0.0",
"known-css-properties": "^0.36.0",
@ -6352,25 +6489,25 @@
"license": "MIT"
},
"node_modules/stylelint/node_modules/file-entry-cache": {
"version": "10.0.8",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.0.8.tgz",
"integrity": "sha512-FGXHpfmI4XyzbLd3HQ8cbUcsFGohJpZtmQRHr8z8FxxtCe2PcpgIlVLwIgunqjvRmXypBETvwhV4ptJizA+Y1Q==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-10.1.0.tgz",
"integrity": "sha512-Et/ex6smi3wOOB+n5mek+Grf7P2AxZR5ueqRUvAAn4qkyatXi3cUC1cuQXVkX0VlzBVsN4BkWJFmY/fYiRTdww==",
"dev": true,
"license": "MIT",
"dependencies": {
"flat-cache": "^6.1.8"
"flat-cache": "^6.1.9"
}
},
"node_modules/stylelint/node_modules/flat-cache": {
"version": "6.1.8",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.8.tgz",
"integrity": "sha512-R6MaD3nrJAtO7C3QOuS79ficm2pEAy++TgEUD8ii1LVlbcgZ9DtASLkt9B+RZSFCzm7QHDMlXPsqqB6W2Pfr1Q==",
"version": "6.1.9",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.9.tgz",
"integrity": "sha512-DUqiKkTlAfhtl7g78IuwqYM+YqvT+as0mY+EVk6mfimy19U79pJCzDZQsnqk3Ou/T6hFXWLGbwbADzD/c8Tydg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cacheable": "^1.8.9",
"cacheable": "^1.9.0",
"flatted": "^3.3.3",
"hookified": "^1.8.1"
"hookified": "^1.8.2"
}
},
"node_modules/stylelint/node_modules/globby": {
@ -6405,9 +6542,9 @@
}
},
"node_modules/stylelint/node_modules/ignore": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz",
"integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==",
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.4.tgz",
"integrity": "sha512-gJzzk+PQNznz8ysRrC0aOkBNVRBDtE1n53IqyqEf3PXrYwomFs5q4pGMizBMJF+ykh03insJ27hB8gSrD2Hn8A==",
"dev": true,
"license": "MIT",
"engines": {
@ -6807,9 +6944,9 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "6.3.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz",
"integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==",
"version": "6.3.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz",
"integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6882,17 +7019,17 @@
}
},
"node_modules/vite-plugin-static-copy": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-2.3.1.tgz",
"integrity": "sha512-EfsPcBm3ewg3UMG8RJaC0ADq6/qnUZnokXx4By4+2cAcipjT9i0Y0owIJGqmZI7d6nxk4qB1q5aXOwNuSyPdyA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-3.0.0.tgz",
"integrity": "sha512-Uki9pPUQ4ZnoMEdIFabvoh9h6Bh9Q1m3iF7BrZvoiF30reREpJh2gZb4jOnW1/uYFzyRiLCmFSkM+8hwiq1vWQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.5.3",
"fast-glob": "^3.2.11",
"fs-extra": "^11.1.0",
"fs-extra": "^11.3.0",
"p-map": "^7.0.3",
"picocolors": "^1.0.0"
"picocolors": "^1.1.1",
"tinyglobby": "^0.2.13"
},
"engines": {
"node": "^18.0.0 || >=20.0.0"
@ -7004,9 +7141,9 @@
}
},
"node_modules/webpack": {
"version": "5.99.7",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.7.tgz",
"integrity": "sha512-CNqKBRMQjwcmKR0idID5va1qlhrqVUKpovi+Ec79ksW8ux7iS1+A6VqzfZXgVYCFRKl7XL5ap3ZoMpwBJxcg0w==",
"version": "5.99.9",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
"integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==",
"dev": true,
"license": "MIT",
"dependencies": {

View file

@ -9,33 +9,30 @@
"icons.html": "node theme_icons.js"
},
"devDependencies": {
"@eslint/js": "^9.25.1",
"@eslint/js": "^9.27.0",
"copy-webpack-plugin": "^13.0.0",
"css-loader": "^7.1.2",
"edge.js": "^6.2.1",
"eslint": "^9.25.1",
"eslint": "^9.27.0",
"filemanager-webpack-plugin": "^8.0.0",
"globals": "^16.0.0",
"ionicons": "^7.4.0",
"globals": "^16.2.0",
"ionicons": "^8.0.8",
"leaflet": "^1.9.4",
"less": "^4.3.0",
"less-loader": "^12.3.0",
"normalize.css": "^8.0.1",
"sharp": "^0.34.1",
"sharp": "^0.34.2",
"style-loader": "^4.0.0",
"stylelint": "^16.19.1",
"stylelint": "^16.20.0",
"stylelint-config-standard": "^38.0.0",
"stylelint-config-standard-less": "^3.0.1",
"stylelint-prettier": "^5.0.3",
"svgo": "^3.3.2",
"swiped-events": "^1.2.0",
"vite": "^6.3.4",
"vite-plugin-static-copy": "^2.3.1",
"vite": "^6.3.5",
"vite-plugin-static-copy": "^3.0.0",
"vite-plugin-stylelint": "^6.0.0",
"webpack": "^5.99.7",
"webpack": "^5.99.9",
"webpack-cli": "^6.0.1"
},
"dependencies": {
"autocomplete-js": "^2.7.1"
}
}

View file

@ -1,14 +1,13 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* exported AutoComplete */
import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomplete.js";
(function (w, d, searxng) {
'use strict';
var qinput_id = "q", qinput;
const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches;
const isResultsPage = document.querySelector("main").id == "main_results";
function submitIfQuery () {
if (qinput.value.length > 0) {
@ -38,8 +37,62 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
qinput.addEventListener('input', updateClearButton, false);
}
const fetchResults = async (query) => {
let request;
if (searxng.settings.method === 'GET') {
const reqParams = new URLSearchParams();
reqParams.append("q", query);
request = fetch("./autocompleter?" + reqParams.toString());
} else {
const formData = new FormData();
formData.append("q", query);
request = fetch("./autocompleter", {
method: 'POST',
body: formData,
});
}
request.then(async function (response) {
const results = await response.json();
if (!results) return;
const autocomplete = d.querySelector(".autocomplete");
const autocompleteList = d.querySelector(".autocomplete ul");
autocomplete.classList.add("open");
autocompleteList.innerHTML = "";
// show an error message that no result was found
if (!results[1] || results[1].length == 0) {
const noItemFoundMessage = document.createElement("li");
noItemFoundMessage.classList.add('no-item-found');
noItemFoundMessage.innerHTML = searxng.settings.translations.no_item_found;
autocompleteList.appendChild(noItemFoundMessage);
return;
}
for (let result of results[1]) {
const li = document.createElement("li");
li.innerText = result;
searxng.on(li, 'mousedown', () => {
qinput.value = result;
const form = d.querySelector("#search");
form.submit();
autocomplete.classList.remove('open');
});
autocompleteList.appendChild(li);
}
});
};
searxng.ready(function () {
// focus search input on large screens
if (!isMobile && !isResultsPage) document.getElementById("q").focus();
qinput = d.getElementById(qinput_id);
const autocomplete = d.querySelector(".autocomplete");
const autocompleteList = d.querySelector(".autocomplete ul");
if (qinput !== null) {
// clear button
@ -47,109 +100,45 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
// autocompleter
if (searxng.settings.autocomplete) {
searxng.autocomplete = AutoComplete.call(w, {
Url: "./autocompleter",
EmptyMessage: searxng.settings.translations.no_item_found,
HttpMethod: searxng.settings.method,
HttpHeaders: {
"Content-type": "application/x-www-form-urlencoded",
"X-Requested-With": "XMLHttpRequest"
},
MinChars: searxng.settings.autocomplete_min,
Delay: 300,
_Position: function () {},
_Open: function () {
var params = this;
Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"), function (li) {
if (li.getAttribute("class") != "locked") {
li.onmousedown = function () {
params._Select(li);
};
}
});
},
_Select: function (item) {
AutoComplete.defaults._Select.call(this, item);
var form = item.closest('form');
if (form) {
form.submit();
searxng.on(qinput, 'input', () => {
const query = qinput.value;
if (query.length < searxng.settings.autocomplete_min) return;
setTimeout(() => {
if (query == qinput.value) fetchResults(query);
}, 300);
});
searxng.on(qinput, 'keyup', (e) => {
let currentIndex = -1;
const listItems = autocompleteList.children;
for (let i = 0; i < listItems.length; i++) {
if (listItems[i].classList.contains('active')) {
currentIndex = i;
break;
}
},
_MinChars: function () {
if (this.Input.value.indexOf('!') > -1) {
return 0;
} else {
return AutoComplete.defaults._MinChars.call(this);
}
},
KeyboardMappings: Object.assign({}, AutoComplete.defaults.KeyboardMappings, {
"KeyUpAndDown_up": Object.assign({}, AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up, {
Callback: function (event) {
AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up.Callback.call(this, event);
var liActive = this.DOMResults.querySelector("li.active");
if (liActive) {
AutoComplete.defaults._Select.call(this, liActive);
}
},
}),
"Tab": Object.assign({}, AutoComplete.defaults.KeyboardMappings.Enter, {
Conditions: [{
Is: 9,
Not: false
}],
Callback: function (event) {
if (this.DOMResults.getAttribute("class").indexOf("open") != -1) {
var liActive = this.DOMResults.querySelector("li.active");
if (liActive !== null) {
AutoComplete.defaults._Select.call(this, liActive);
event.preventDefault();
}
}
},
})
}),
}, "#" + qinput_id);
}
/*
Monkey patch autocomplete.js to fix a bug
With the POST method, the values are not URL encoded: query like "1 + 1" are sent as "1 1" since space are URL encoded as plus.
See HTML specifications:
* HTML5: https://url.spec.whatwg.org/#concept-urlencoded-serializer
* HTML4: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
autocomplete.js does not URL encode the name and values:
https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/src/autocomplete.ts#L665
The monkey patch overrides the compiled version of the ajax function.
See https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/dist/autocomplete.js#L143-L158
The patch changes only the line 156 from
params.Request.send(params._QueryArg() + "=" + params._Pre());
to
params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre()));
Related to:
* https://github.com/autocompletejs/autocomplete.js/issues/78
* https://github.com/searxng/searxng/issues/1695
*/
AutoComplete.prototype.ajax = function (params, request, timeout) {
if (timeout === void 0) { timeout = true; }
if (params.$AjaxTimer) {
window.clearTimeout(params.$AjaxTimer);
}
if (timeout === true) {
params.$AjaxTimer = window.setTimeout(AutoComplete.prototype.ajax.bind(null, params, request, false), params.Delay);
} else {
if (params.Request) {
params.Request.abort();
}
params.Request = request;
params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre()));
}
};
if (!isMobile && document.querySelector('.index_endpoint')) {
qinput.focus();
let newCurrentIndex = -1;
if (e.key === "ArrowUp") {
if (currentIndex >= 0) listItems[currentIndex].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;
} else if (e.key === "ArrowDown") {
if (currentIndex >= 0) listItems[currentIndex].classList.remove('active');
newCurrentIndex = (currentIndex + 1) % listItems.length;
} else if (e.key === "Tab" || e.key === "Enter") {
autocomplete.classList.remove('open');
}
if (newCurrentIndex != -1) {
const selectedItem = listItems[newCurrentIndex];
selectedItem.classList.add('active');
if (!selectedItem.classList.contains('no-item-found')) qinput.value = selectedItem.innerText;
}
});
}
}
@ -184,7 +173,7 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
categoryButton.classList.remove("selected");
}
button.classList.add("selected");
})
});
}
// override form submit action to update the actually selected categories

View file

@ -3,6 +3,7 @@
.autocomplete {
position: absolute;
width: @search-width;
max-width: calc(100% - 2 * @search-padding-horizontal);
max-height: 0;
overflow-y: hidden;
.ltr-text-align-left();
@ -65,8 +66,6 @@
@media screen and (max-width: @phone) {
.autocomplete {
width: 100%;
> ul > li {
padding: 1rem;
}

View file

@ -287,8 +287,9 @@
@results-image-row-height: 12rem;
@results-image-row-height-phone: 10rem;
@search-width: 44rem;
// heigh of #search, see detail.less
// height of #search, see detail.less
@search-height: 13rem;
@search-padding-horizontal: 0.5rem;
/// Device Size
/// @desktop > @tablet

View file

@ -131,7 +131,7 @@ button.category_button {
}
#search_view {
padding: 0.5rem 0.3rem 0 0.5rem;
padding: 0.5rem @search-padding-horizontal 0 @search-padding-horizontal;
grid-area: search;
body.results_endpoint & {
@ -141,7 +141,8 @@ button.category_button {
.search_box {
border-radius: 0.8rem;
width: @search-width;
width: 100%;
max-width: @search-width;
display: inline-flex;
flex-direction: row;
white-space: nowrap;
@ -291,8 +292,7 @@ html.no-js #clear_search.hide_if_nojs {
}
.search_box {
width: 98%;
display: flex;
width: 100%;
}
#q {

View file

@ -51,11 +51,13 @@ function jinja_svg_catalog(dest, macros, items) {
(item) => {
/** @type {import("svgo").Config} */
// JSON.stringify & JSON.parse are used to create a deep copy of the
// item.svgo_opts object
const svgo_opts = JSON.parse(JSON.stringify(item.svgo_opts));
svgo_opts.plugins.push({
name: "addAttributesToSVGElement",
name: "addClassesToSVGElement",
params: {
attributes: [{ "class": __jinja_class_placeholder__, }]
classNames: [__jinja_class_placeholder__]
}}
);

65
container/Dockerfile Normal file
View file

@ -0,0 +1,65 @@
FROM ghcr.io/searxng/base:searxng-builder AS builder
COPY ./requirements.txt ./requirements.txt
RUN --mount=type=cache,id=pip,target=/root/.cache/pip python -m venv ./venv \
&& . ./venv/bin/activate \
&& pip install -r requirements.txt \
&& pip install "uwsgi~=2.0"
COPY ./searx/ ./searx/
ARG TIMESTAMP_SETTINGS="0"
RUN python -m compileall -q searx \
&& touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \
&& find ./searx/static \
\( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" -o -name "*.ttf" -o -name "*.eot" \) \
-type f -exec gzip -9 -k {} + -exec brotli --best {} +
FROM ghcr.io/searxng/base:searxng AS dist
ARG LABEL_DATE="0001-01-01T00:00:00Z"
ARG GIT_URL="unspecified"
ARG SEARXNG_GIT_VERSION="unspecified"
ARG LABEL_VCS_REF="unspecified"
ARG LABEL_VCS_URL="unspecified"
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/
COPY --chown=searxng:searxng ./container/config/ ./.template/
COPY --chown=searxng:searxng ./container/entrypoint.sh ./entrypoint.sh
ARG TIMESTAMP_UWSGI="0"
RUN touch -c --date=@$TIMESTAMP_UWSGI ./.template/uwsgi.ini
LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \
org.opencontainers.image.created="$LABEL_DATE" \
org.opencontainers.image.description="A privacy-respecting, hackable metasearch engine" \
org.opencontainers.image.documentation="https://github.com/searxng/searxng-docker" \
org.opencontainers.image.licenses="AGPL-3.0-or-later" \
org.opencontainers.image.revision="$LABEL_VCS_REF" \
org.opencontainers.image.source="$LABEL_VCS_URL" \
org.opencontainers.image.title="searxng" \
org.opencontainers.image.url="$LABEL_VCS_URL" \
org.opencontainers.image.version="$SEARXNG_GIT_VERSION"
ENV SEARXNG_VERSION="$SEARXNG_GIT_VERSION" \
INSTANCE_NAME="SearXNG" \
AUTOCOMPLETE="" \
BASE_URL="" \
BIND_ADDRESS="[::]:8080" \
SEARXNG_SETTINGS_PATH="$CONFIG_PATH/settings.yml" \
UWSGI_SETTINGS_PATH="$CONFIG_PATH/uwsgi.ini" \
UWSGI_WORKERS="%k" \
UWSGI_THREADS="4"
VOLUME $CONFIG_PATH
VOLUME $DATA_PATH
EXPOSE 8080
HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1
ENTRYPOINT ["/usr/local/searxng/entrypoint.sh"]

View file

@ -0,0 +1,25 @@
contents:
keyring:
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
repositories:
- https://packages.wolfi.dev/os
packages:
- wolfi-base
- build-base
- python-3.13-dev
- py3-pip
- brotli
entrypoint:
command: /bin/sh -l
work-dir: /usr/local/searxng/
environment:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
HISTFILE: /dev/null
archs:
- x86_64
- aarch64

61
container/base.yml Normal file
View file

@ -0,0 +1,61 @@
contents:
keyring:
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
repositories:
- https://packages.wolfi.dev/os
packages:
- wolfi-baselayout
- ca-certificates-bundle
- busybox
- python-3.13
# healthcheck
- wget
# uwsgi
- mailcap
entrypoint:
command: /bin/sh -l
work-dir: /usr/local/searxng/
accounts:
groups:
- groupname: searxng
gid: 977
users:
- username: searxng
uid: 977
shell: /bin/ash
environment:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
HISTFILE: /dev/null
CONFIG_PATH: /etc/searxng
DATA_PATH: /var/cache/searxng
paths:
# Workdir
- path: /usr/local/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
# Config volume
- path: /etc/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
# Data volume
- path: /var/cache/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
archs:
- x86_64
- aarch64

166
container/entrypoint.sh Executable file
View file

@ -0,0 +1,166 @@
#!/bin/sh
# shellcheck shell=dash
set -u
check_file() {
local target="$1"
if [ ! -f "$target" ]; then
cat <<EOF
!!!
!!! ERROR
!!! "$target" is not a valid file, exiting...
!!!
EOF
exit 127
fi
}
check_directory() {
local target="$1"
if [ ! -d "$target" ]; then
cat <<EOF
!!!
!!! ERROR
!!! "$target" is not a valid directory, exiting...
!!!
EOF
exit 127
fi
}
setup_ownership() {
local target="$1"
local type="$2"
case "$type" in
file | directory) ;;
*)
cat <<EOF
!!!
!!! ERROR
!!! "$type" is not a valid type, exiting...
!!!
EOF
exit 1
;;
esac
if [ "$(stat -c %U:%G "$target")" != "searxng:searxng" ]; then
if [ "$(id -u)" -eq 0 ]; then
chown -R searxng:searxng "$target"
else
cat <<EOF
!!!
!!! WARNING
!!! "$target" $type is not owned by "searxng"
!!! This may cause issues when running SearXNG
!!!
!!! Run the container as root to fix this issue automatically
!!! Alternatively, you can chown the $type manually:
!!! $ chown -R searxng:searxng "$target"
!!!
EOF
fi
fi
}
# Apply envs to uwsgi.ini
setup_uwsgi() {
local timestamp
timestamp=$(stat -c %Y "$UWSGI_SETTINGS_PATH")
sed -i \
-e "s|workers = .*|workers = ${UWSGI_WORKERS:-%k}|g" \
-e "s|threads = .*|threads = ${UWSGI_THREADS:-4}|g" \
"$UWSGI_SETTINGS_PATH"
# Restore timestamp
touch -c -d "@$timestamp" "$UWSGI_SETTINGS_PATH"
}
# Apply envs to settings.yml
setup_searxng() {
local timestamp
timestamp=$(stat -c %Y "$SEARXNG_SETTINGS_PATH")
# Ensure trailing slash in BASE_URL
# https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion
export BASE_URL="${BASE_URL%/}/"
sed -i \
-e "s|base_url: false|base_url: ${BASE_URL:-false}|g" \
-e "s/instance_name: \"SearXNG\"/instance_name: \"${INSTANCE_NAME:-SearXNG}\"/g" \
-e "s/autocomplete: \"\"/autocomplete: \"${AUTOCOMPLETE:-}\"/g" \
-e "s/ultrasecretkey/$(head -c 24 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')/g" \
"$SEARXNG_SETTINGS_PATH"
# Restore timestamp
touch -c -d "@$timestamp" "$SEARXNG_SETTINGS_PATH"
}
# Handle volume mounts
volume_handler() {
local target="$1"
# Check if it's a valid directory
check_directory "$target"
setup_ownership "$target" "directory"
}
# Handle configuration file updates
config_handler() {
local target="$1"
local template="$2"
local new_template_target="$target.new"
# Create/Update the configuration file
if [ -f "$target" ]; then
setup_ownership "$target" "file"
if [ "$template" -nt "$target" ]; then
cp -pfT "$template" "$new_template_target"
cat <<EOF
...
... INFORMATION
... Update available for "$target"
... It is recommended to update the configuration file to ensure proper functionality
...
... New version placed at "$new_template_target"
... Please review and merge changes
...
EOF
fi
else
cat <<EOF
...
... INFORMATION
... "$target" does not exist, creating from template...
...
EOF
cp -pfT "$template" "$target"
fi
# Check if it's a valid file
check_file "$target"
}
echo "SearXNG $SEARXNG_VERSION"
# Check for volume mounts
volume_handler "$CONFIG_PATH"
volume_handler "$DATA_PATH"
# Check for updates in files
config_handler "$UWSGI_SETTINGS_PATH" "/usr/local/searxng/.template/uwsgi.ini"
config_handler "$SEARXNG_SETTINGS_PATH" "/usr/local/searxng/searx/settings.yml"
# Update files
setup_uwsgi
setup_searxng
exec /usr/local/searxng/venv/bin/uwsgi --http-socket "$BIND_ADDRESS" "$UWSGI_SETTINGS_PATH"

View file

@ -16,8 +16,7 @@ WORKDIR /usr/local/searxng/
COPY ./requirements.txt ./requirements.txt
# Readd on #4707 "--mount=type=cache,id=pip,target=/root/.cache/pip"
RUN python -m venv ./venv \
RUN --mount=type=cache,id=pip,target=/root/.cache/pip python -m venv ./venv \
&& . ./venv/bin/activate \
&& pip install -r requirements.txt \
&& pip install "uwsgi~=2.0"
@ -25,11 +24,9 @@ RUN python -m venv ./venv \
COPY ./searx/ ./searx/
ARG TIMESTAMP_SETTINGS=0
ARG TIMESTAMP_UWSGI=0
RUN python -m compileall -q searx \
&& touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \
&& touch -c --date=@$TIMESTAMP_UWSGI ./dockerfiles/uwsgi.ini \
&& find /usr/local/searxng/searx/static \
\( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.svg' -o -name '*.ttf' -o -name '*.eot' \) \
-type f -exec gzip -9 -k {} + -exec brotli --best {} +
@ -69,7 +66,12 @@ WORKDIR /usr/local/searxng/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/
COPY --chown=searxng:searxng ./dockerfiles/ ./dockerfiles/
COPY --chown=searxng:searxng ./container/config/ ./.template/
COPY --chown=searxng:searxng ./container/entrypoint.sh ./entrypoint.sh
ARG TIMESTAMP_UWSGI="0"
RUN touch -c --date=@$TIMESTAMP_UWSGI ./.template/uwsgi.ini
LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \
org.opencontainers.image.created=$LABEL_DATE \
@ -90,8 +92,6 @@ ENV SEARXNG_VERSION=$SEARXNG_GIT_VERSION \
AUTOCOMPLETE="" \
BASE_URL="" \
BIND_ADDRESS=[::]:8080 \
MORTY_KEY="" \
MORTY_URL="" \
SEARXNG_SETTINGS_PATH=$CONFIG_PATH/settings.yml \
UWSGI_SETTINGS_PATH=$CONFIG_PATH/uwsgi.ini \
UWSGI_WORKERS=%k \
@ -104,4 +104,4 @@ EXPOSE 8080
HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1
ENTRYPOINT ["/usr/local/searxng/dockerfiles/docker-entrypoint.sh"]
ENTRYPOINT ["/usr/local/searxng/entrypoint.sh"]

View file

@ -1,167 +0,0 @@
#!/bin/sh
help() {
cat <<EOF
Command line:
-h Display this help
-d Dry run to update the configuration files.
-f Always update on the configuration files (existing files are renamed with
the .old suffix). Without this option, the new configuration files are
copied with the .new suffix
Environment variables:
INSTANCE_NAME settings.yml : general.instance_name
AUTOCOMPLETE settings.yml : search.autocomplete
BASE_URL settings.yml : server.base_url
MORTY_URL settings.yml : result_proxy.url
MORTY_KEY settings.yml : result_proxy.key
Volume:
/etc/searxng the docker entry point copies settings.yml and uwsgi.ini in
this directory (see the -f command line option)"
EOF
}
# Parse command line
FORCE_CONF_UPDATE=0
DRY_RUN=0
while getopts "fdh" option
do
case $option in
f) FORCE_CONF_UPDATE=1 ;;
d) DRY_RUN=1 ;;
h)
help
exit 0
;;
*)
echo "unknow option ${option}"
exit 42
;;
esac
done
echo "SearXNG version $SEARXNG_VERSION"
# helpers to update the configuration files
patch_uwsgi_settings() {
CONF="$1"
# update uwsg.ini
sed -i \
-e "s|workers = .*|workers = ${UWSGI_WORKERS:-%k}|g" \
-e "s|threads = .*|threads = ${UWSGI_THREADS:-4}|g" \
"${CONF}"
}
patch_searxng_settings() {
CONF="$1"
# Make sure that there is trailing slash at the end of BASE_URL
# see https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion
export BASE_URL="${BASE_URL%/}/"
# update settings.yml
sed -i \
-e "s|base_url: false|base_url: ${BASE_URL}|g" \
-e "s/instance_name: \"SearXNG\"/instance_name: \"${INSTANCE_NAME}\"/g" \
-e "s/autocomplete: \"\"/autocomplete: \"${AUTOCOMPLETE}\"/g" \
-e "s/ultrasecretkey/$(head -c 24 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')/g" \
"${CONF}"
# Morty configuration
if [ -n "${MORTY_KEY}" ] && [ -n "${MORTY_URL}" ]; then
sed -i -e "s/image_proxy: false/image_proxy: true/g" \
"${CONF}"
cat >> "${CONF}" <<-EOF
# Morty configuration
result_proxy:
url: ${MORTY_URL}
key: !!binary "${MORTY_KEY}"
EOF
fi
}
update_conf() {
FORCE_CONF_UPDATE=$1
CONF="$2"
NEW_CONF="${2}.new"
OLD_CONF="${2}.old"
REF_CONF="$3"
PATCH_REF_CONF="$4"
if [ -f "${CONF}" ]; then
if [ "${REF_CONF}" -nt "${CONF}" ]; then
# There is a new version
if [ "$FORCE_CONF_UPDATE" -ne 0 ]; then
# Replace the current configuration
printf '⚠️ Automatically update %s to the new version\n' "${CONF}"
if [ ! -f "${OLD_CONF}" ]; then
printf 'The previous configuration is saved to %s\n' "${OLD_CONF}"
mv "${CONF}" "${OLD_CONF}"
fi
cp "${REF_CONF}" "${CONF}"
$PATCH_REF_CONF "${CONF}"
else
# Keep the current configuration
printf '⚠️ Check new version %s to make sure SearXNG is working properly\n' "${NEW_CONF}"
cp "${REF_CONF}" "${NEW_CONF}"
$PATCH_REF_CONF "${NEW_CONF}"
fi
else
printf 'Use existing %s\n' "${CONF}"
fi
else
printf 'Create %s\n' "${CONF}"
cp "${REF_CONF}" "${CONF}"
$PATCH_REF_CONF "${CONF}"
fi
}
# searx compatibility: copy /etc/searx/* to /etc/searxng/*
SEARX_CONF=0
if [ -f "/etc/searx/settings.yml" ]; then
if [ ! -f "${SEARXNG_SETTINGS_PATH}" ]; then
printf '⚠️ /etc/searx/settings.yml is copied to /etc/searxng\n'
cp "/etc/searx/settings.yml" "${SEARXNG_SETTINGS_PATH}"
fi
SEARX_CONF=1
fi
if [ -f "/etc/searx/uwsgi.ini" ]; then
printf '⚠️ /etc/searx/uwsgi.ini is ignored. Use the volume /etc/searxng\n'
SEARX_CONF=1
fi
if [ "$SEARX_CONF" -eq "1" ]; then
printf '⚠️ The deprecated volume /etc/searx is mounted. Please update your configuration to use /etc/searxng ⚠️\n'
cat << EOF > /etc/searx/deprecated_volume_read_me.txt
This Docker image uses the volume /etc/searxng
Update your configuration:
* remove uwsgi.ini (or very carefully update your existing uwsgi.ini using https://github.com/searxng/searxng/blob/master/dockerfiles/uwsgi.ini )
* mount /etc/searxng instead of /etc/searx
EOF
fi
# end of searx compatibility
# make sure there are uwsgi settings
update_conf "${FORCE_CONF_UPDATE}" "${UWSGI_SETTINGS_PATH}" "/usr/local/searxng/dockerfiles/uwsgi.ini" "patch_uwsgi_settings"
# make sure there are searxng settings
update_conf "${FORCE_CONF_UPDATE}" "${SEARXNG_SETTINGS_PATH}" "/usr/local/searxng/searx/settings.yml" "patch_searxng_settings"
# dry run (to update configuration files, then inspect them)
if [ $DRY_RUN -eq 1 ]; then
printf 'Dry run\n'
exit
fi
unset MORTY_KEY
printf 'Listen on %s\n' "${BIND_ADDRESS}"
# Start uwsgi
# TODO: "--http-socket" will be removed in the future (see uwsgi.ini.new config file): https://github.com/searxng/searxng/pull/4578
exec /usr/local/searxng/venv/bin/uwsgi --http-socket "${BIND_ADDRESS}" "${UWSGI_SETTINGS_PATH}"

View file

@ -6,7 +6,7 @@ digraph G {
browser [label="browser", shape=tab, fillcolor=aliceblue];
rp [label="reverse proxy"];
static [label="static files", shape=folder, href="url to configure static files", fillcolor=lightgray];
uwsgi [label="uwsgi", shape=parallelogram href="https://docs.searxng.org/utils/searx.sh.html"]
uwsgi [label="uwsgi", shape=parallelogram href="https://docs.searxng.org/utils/searxng.sh.html"]
redis [label="redis DB", shape=cylinder];
searxng1 [label="SearXNG #1", fontcolor=blue3];
searxng2 [label="SearXNG #2", fontcolor=blue3];

View file

@ -145,13 +145,6 @@ shell inside container
- `How to make bash scripts work in dash <http://mywiki.wooledge.org/Bashism>`_
- `Checking for Bashisms <https://dev.to/bowmanjd/writing-bash-scripts-that-are-not-only-bash-checking-for-bashisms-and-testing-with-dash-1bli>`_
Like in many other distributions, Alpine's `/bin/sh
<https://wiki.ubuntu.com/DashAsBinSh>`__ is :man:`dash`. Dash is meant to be
`POSIX-compliant <https://pubs.opengroup.org/onlinepubs/9699919799>`__.
Compared to debian, in the Alpine image :man:`bash` is not installed. The
:origin:`dockerfiles/docker-entrypoint.sh` script is checked *against dash*
(``make tests.shell``).
To open a shell inside the container:
.. code:: sh
@ -188,10 +181,10 @@ Command line
<https://docs.docker.com/engine/reference/run/#foreground>`__.
In the :origin:`Dockerfile` the ENTRYPOINT_ is defined as
:origin:`dockerfiles/docker-entrypoint.sh`
:origin:`container/entrypoint.sh`
.. code:: sh
docker run --rm -it searxng/searxng -h
.. program-output:: ../dockerfiles/docker-entrypoint.sh -h
.. program-output:: ../container/entrypoint.sh -h

View file

@ -41,6 +41,7 @@
- ``duckduckgo``
- ``google``
- ``mwmbl``
- ``naver``
- ``quark``
- ``qwant``
- ``seznam``

View file

@ -58,9 +58,6 @@ and then, to name just a few:
- Bot protection has been switched from filtron to SearXNG's :ref:`limiter
<limiter>`, this requires a :ref:`Redis <settings redis>` database.
- The image proxy morty is no longer needed, it has been replaced by the
:ref:`image proxy <image_proxy>` from SearXNG.
- To save bandwidth :ref:`cache busting <static_use_hash>` has been implemented.
To get in use, the ``static-expires`` needs to be set in the :ref:`uwsgi
setup`.
@ -71,12 +68,6 @@ examples show, this is not always enough, sometimes services have to be set up
or reconfigured and sometimes services that are no longer needed should be
uninstalled.
.. hint::
First of all: SearXNG is installed by the script :ref:`searxng.sh`. If you
have old filtron, morty or searx setup you should consider complete
uninstall/reinstall.
Here you will find a list of changes that affect the infrastructure. Please
check to what extent it is necessary to update your installations:
@ -85,39 +76,6 @@ check to what extent it is necessary to update your installations:
file manually.
remove obsolete services
------------------------
If your searx instance was installed *"Step by step"* or by the *"Installation
scripts"*, you need to undo the installation procedure completely. If you have
morty & filtron installed, it is recommended to uninstall these services also.
In case of scripts, to uninstall use the scripts from the origin you installed
searx from or try::
$ sudo -H ./utils/filtron.sh remove all
$ sudo -H ./utils/morty.sh remove all
$ sudo -H ./utils/searx.sh remove all
.. hint::
If you are migrate from searx take into account that the ``.config.sh`` is no
longer used.
If you upgrade from searx or from before :pull:`1332` has been merged and you
have filtron and/or morty installed, don't forget to remove HTTP sites.
Apache::
$ sudo -H ./utils/filtron.sh apache remove
$ sudo -H ./utils/morty.sh apache remove
nginx::
$ sudo -H ./utils/filtron.sh nginx remove
$ sudo -H ./utils/morty.sh nginx remove
Check after Installation
------------------------
@ -130,9 +88,6 @@ to see if there are some left overs. In this example there exists a *old*
SearXNG checks
--------------
ERROR: settings.yml in /etc/searx/ is deprecated, move file to folder /etc/searxng/
INFO: [OK] (old) account 'searx' does not exists
INFO: [OK] (old) account 'filtron' does not exists
INFO: [OK] (old) account 'morty' does not exists
...
INFO searx.redisdb : connecting to Redis db=0 path='/usr/local/searxng-redis/run/redis.sock'
INFO searx.redisdb : connected to Redis

108
docs/dev/commits.rst Normal file
View file

@ -0,0 +1,108 @@
.. _create commit:
===============================
Git Commits & Change Management
===============================
.. sidebar:: Create good commits!
- `Conventional Commits`_
- `Structural split of changes`_
- `Git Commit Good Practice`_
A commit and its commit message are among the most important information
available to a developer for bug fixing and further development. A commit is a
change and changes have a context (a change request).
In a SCM system (git), the change history is derived from the commit history. A
commit message is therefore part of the documentation for change management and
thus elementary for the traceability of changes.
**What a commit is not**: *A commit to an SCM system is not used to save files!*
A commit should always have a context and the commit message describes what is
to be changed in that context, just as a function description should describe
what the intention and the goal of the function is, a commit message should
describe what the intention and the goal of that commit is.
The commit messages form the history and are the first and therefore most
important information a developer has when he has to research when and why a
change had to be made and how it was made (what the goal was).
Like any text, a commit message should be written for the reader and not from
the perspective of the author.
When scrolling through the history, the first thing one see is the title of the
commit message. Therefore the title should describe the change as briefly and
precisely as possible ... followed by a blank line and then a somewhat detailed
description of the change.
----
The follwing rules should be in mind, when creating a commit:
- **Commit history should be read like a history book.**
- **Commit messages are for the reader not for the author of the commit.**
- **A commit is the atomic code-modification of a change in change management.**
- **Think about which descriptions from your PR might belong in the commit message.**
- **The maximum line length in a commit message is 80 characters.**
----
Choose meaningful commit messages:
.. code::
[type] optional scope: description
[body]
[optional trailers]
``[type]``:
Commits MUST be prefixed with a type .. ``feat``, ``fix``, ``refactor``,
``mod``, ``upd``, ``doc``, ``l10n``, ``build`` ..
``[body]``
`Information in commit messages`_
``[optional trailers]``:
- `Signed-off-by`_: certify that the committer has the rights to submit the
work under the projects license. That the developer has this right is a
prerequisite for a merge. If the `Signed-off-by`_ is not set in the
commit, the contributor enters his `Developer's Certificate of Origin` at
the latest when creating a PR!
- Closes: Link to the bug report or the bug number (e.g. ``Closes: #10``)
- `Co-authored-by`_: email address of the co-author
- Reported-by: email address (if there is no bug report)
- Suggested-by: email address (if there is no bug report)
----
To give examples at hand, here are a few commits. Follow the links to see the
full commit messages:
:patch:`44d941c93`
``[fix] mojeek web engine: don't add empty fmt argument for web searches``
:patch:`feb15e387`
``[fix] brave.news engine: response is HTML and no longer JSON``
:patch:`bdfe1c2a1`
``[mod] engines: migration of the individual cache solutions to EngineCache``
.. _Conventional Commits:
https://www.conventionalcommits.org/
.. _Structural split of changes:
https://wiki.openstack.org/wiki/GitCommitMessages#Structural_split_of_changes
.. _Git Commit Good Practice:
https://wiki.openstack.org/wiki/GitCommitMessages
.. _Information in commit messages:
https://wiki.openstack.org/wiki/GitCommitMessages#Information_in_commit_messages
.. _`Developer's Certificate of Origin`:
https://developercertificate.org/
.. _Signed-off-by:
https://git-scm.com/docs/git-commit#Documentation/git-commit.txt-code--signoffcode
.. _Co-authored-by:
https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors

View file

@ -30,15 +30,15 @@ SearXNG was born out of the need for a **privacy-respecting** search tool which
can be extended easily to maximize both its search and its privacy protecting
capabilities.
Some widely used search engine features may work differently,
may be turned off by default, or may not be implemented at all in SearXNG
Some widely used search engine features may work differently,
may be turned off by default, or may not be implemented at all in SearXNG
**as a consequence of a privacy-by-design approach**.
Following this approach, features reducing the privacy preserving aspects of SearXNG should be
switched off by default or should not be implemented at all. There are plenty of
search engines already providing such features. If a feature reduces
SearXNG's efficacy in protecting a user's privacy, the user must be informed about
the effect of choosing to enable it. Features that protect privacy but differ from the
SearXNG's efficacy in protecting a user's privacy, the user must be informed about
the effect of choosing to enable it. Features that protect privacy but differ from the
expectations of the user should also be carefully explained to them.
Also, if you think that something works weird with SearXNG, it might be because
@ -56,20 +56,12 @@ Code
====
.. _PEP8: https://www.python.org/dev/peps/pep-0008/
.. _Conventional Commits: https://www.conventionalcommits.org/
.. _Git Commit Good Practice: https://wiki.openstack.org/wiki/GitCommitMessages
.. _Structural split of changes:
https://wiki.openstack.org/wiki/GitCommitMessages#Structural_split_of_changes
.. _gitmoji: https://gitmoji.carloscuesta.me/
.. _Semantic PR: https://github.com/zeke/semantic-pull-requests
.. sidebar:: Create good commits!
- `Structural split of changes`_
- `Conventional Commits`_
- `Git Commit Good Practice`_
- some like to use: gitmoji_
- not yet active: `Semantic PR`_
- :ref:`create commit`
In order to submit a patch, please follow the steps below:
@ -88,15 +80,7 @@ In order to submit a patch, please follow the steps below:
- Add yourself to the :origin:`AUTHORS.rst` file.
- Choose meaningful commit messages, read `Conventional Commits`_
.. code::
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
- Choose meaningful commit messages, see :ref:`create commit`
- Create a pull request.
@ -161,7 +145,7 @@ changed (:ref:`make docs.clean`).
Live builds are implemented by sphinx-autobuild_. Use environment
``$(SPHINXOPTS)`` to pass arguments to the sphinx-autobuild_ command. You can
pass any argument except for the ``--host`` option (which is always set to ``0.0.0.0``).
pass any argument except for the ``--host`` option (which is always set to ``0.0.0.0``).
E.g., to find and use a free port, use:
.. code:: sh

View file

@ -6,6 +6,7 @@ Developer documentation
:maxdepth: 2
quickstart
commits
rtm_asdf
contribution_guide
extended_types

View file

@ -319,13 +319,13 @@ To *inspect* the SearXNG instance (already described above):
.. code:: bash
$ ./utils/searx.sh inspect service
$ ./utils/searxng.sh inspect service
.. group-tab:: desktop (HOST)
.. code:: bash
$ sudo -H ./utils/lxc.sh cmd searxng-archlinux ./utils/searx.sh inspect service
$ sudo -H ./utils/lxc.sh cmd searxng-archlinux ./utils/searxng.sh inspect service
Run :ref:`makefile`, e.g. to test inside the container:
@ -435,4 +435,3 @@ use:
[searxng-archlinux] SEARXNG_URL : http:///n.n.n.140/searxng
[searxng-archlinux] SEARXNG_PORT : 8888
[searxng-archlinux] SEARXNG_BIND_ADDRESS : 127.0.0.1

View file

@ -39,8 +39,7 @@ Removing private data means not sending cookies to external search engines and
generating a random browser profile for every request. Thus, it does not matter
if a public or private instance handles the request, because it is anonymized in
both cases. The IP address used will be the IP of the instance, but SearXNG can also be
configured to use proxy or Tor. `Result proxy
<https://github.com/asciimoo/morty>`__ is supported, too.
configured to use proxy or Tor.
SearXNG does not serve ads or tracking content, unlike most search services. Therefore,
private data is not forwarded to third parties who might monetize it. Besides

View file

@ -28,7 +28,7 @@ In most cases you will install SearXNG simply by running the command:
.. code:: bash
sudo -H ./utils/searx.sh install all
sudo -H ./utils/searxng.sh install all
The installation is described in chapter :ref:`installation basic`.

91
manage
View file

@ -11,6 +11,9 @@ source "$(dirname "${BASH_SOURCE[0]}")/utils/lib.sh"
# shellcheck source=utils/lib.sh
source "$(dirname "${BASH_SOURCE[0]}")/utils/lib_nvm.sh"
# shellcheck source=utils/lib_sxng_container.sh
source "$(dirname "${BASH_SOURCE[0]}")/utils/lib_sxng_container.sh"
# shellcheck source=utils/lib_sxng_data.sh
source "$(dirname "${BASH_SOURCE[0]}")/utils/lib_sxng_data.sh"
@ -77,9 +80,6 @@ docs.:
gh-pages : deploy on gh-pages branch
prebuild : build reST include files (./${DOCS_BUILD}/includes)
clean : clean documentation build
docker.:
build : build docker image
push : build and push docker image
gecko.driver:
download & install geckodriver if not already installed (required for
robot_tests)
@ -101,6 +101,7 @@ EOF
go.help
node.help
weblate.help
container.help
data.help
test.help
themes.help
@ -136,90 +137,6 @@ webapp.run() {
SEARXNG_DEBUG=1 pyenv.cmd python -m searx.webapp
}
docker.push() {
docker.build push
}
docker.buildx() {
docker.build buildx
}
# shellcheck disable=SC2119
docker.build() {
pyenv.install
local SEARXNG_GIT_VERSION
local VERSION_GITCOMMIT
local GITHUB_USER
local SEARXNG_IMAGE_NAME
local BUILD
build_msg DOCKER build
# run installation in a subprocess and activate pyenv
# See https://www.shellcheck.net/wiki/SC1001 and others ..
# shellcheck disable=SC2031,SC2230,SC2002,SC2236,SC2143,SC1001
( set -e
pyenv.activate
# Check if it is a git repository
if [ ! -d .git ]; then
die 1 "This is not Git repository"
fi
if [ ! -x "$(which git)" ]; then
die 1 "git is not installed"
fi
if ! git remote get-url origin 2> /dev/null; then
die 1 "there is no remote origin"
fi
# This is a git repository
git update-index -q --refresh
python -m searx.version freeze
eval "$(python -m searx.version)"
# Get the last git commit id
VERSION_GITCOMMIT=$(echo "$VERSION_TAG" | cut -d+ -f2)
build_msg DOCKER "Last commit : $VERSION_GITCOMMIT"
# define the docker image name
GITHUB_USER=$(echo "${GIT_URL}" | sed 's/.*github\.com\/\([^\/]*\).*/\1/')
SEARXNG_IMAGE_NAME="${SEARXNG_IMAGE_NAME:-${GITHUB_USER:-searxng}/searxng}"
BUILD="build"
if [ "$1" = "buildx" ]; then
# buildx includes the push option
CACHE_TAG="${SEARXNG_IMAGE_NAME}:latest-build-cache"
BUILD="buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 --push --cache-from=type=registry,ref=$CACHE_TAG --cache-to=type=registry,ref=$CACHE_TAG,mode=max"
shift
fi
build_msg DOCKER "Build command: ${BUILD}"
# build Docker image
build_msg DOCKER "Building image ${SEARXNG_IMAGE_NAME}:${SEARXNG_GIT_VERSION}"
# shellcheck disable=SC2086
docker $BUILD \
--build-arg BASE_IMAGE="${DEPENDENCIES_IMAGE_NAME}" \
--build-arg GIT_URL="${GIT_URL}" \
--build-arg SEARXNG_DOCKER_TAG="${DOCKER_TAG}" \
--build-arg SEARXNG_GIT_VERSION="${VERSION_STRING}" \
--build-arg VERSION_GITCOMMIT="${VERSION_GITCOMMIT}" \
--build-arg LABEL_DATE="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--build-arg LABEL_VCS_REF="$(git rev-parse HEAD)" \
--build-arg LABEL_VCS_URL="${GIT_URL}" \
--build-arg TIMESTAMP_SETTINGS="$(git log -1 --format="%cd" --date=unix -- searx/settings.yml)" \
--build-arg TIMESTAMP_UWSGI="$(git log -1 --format="%cd" --date=unix -- dockerfiles/uwsgi.ini)" \
-t "${SEARXNG_IMAGE_NAME}:latest" -t "${SEARXNG_IMAGE_NAME}:${DOCKER_TAG}" .
if [ "$1" = "push" ]; then
docker push "${SEARXNG_IMAGE_NAME}:latest"
docker push "${SEARXNG_IMAGE_NAME}:${DOCKER_TAG}"
fi
)
dump_return $?
}
# shellcheck disable=SC2119
gecko.driver() {
pyenv.install

View file

@ -2,9 +2,9 @@ mock==5.2.0
nose2[coverage_plugin]==0.15.1
cov-core==1.15.0
black==24.3.0
pylint==3.3.6
pylint==3.3.7
splinter==0.21.0
selenium==4.31.0
selenium==4.33.0
Pallets-Sphinx-Themes==2.3.0
Sphinx==7.4.7
sphinx-issues==5.0.1
@ -16,7 +16,7 @@ sphinx-notfound-page==1.1.0
myst-parser==3.0.1
linuxdoc==20240924
aiounittest==1.5.0
yamllint==1.37.0
yamllint==1.37.1
wlc==1.15
coloredlogs==15.0.1
docutils>=0.21.2

View file

@ -1,21 +1,21 @@
certifi==2025.4.26
babel==2.17.0
flask-babel==4.0.0
flask==3.1.0
flask==3.1.1
jinja2==3.1.6
lxml==5.4.0
pygments==2.19.1
python-dateutil==2.9.0.post0
pyyaml==6.0.2
httpx[http2]==0.24.1
httpx[http2]==0.28.1
httpx-socks[asyncio]==0.10.0
Brotli==1.1.0
uvloop==0.21.0
httpx-socks[asyncio]==0.7.7
setproctitle==1.3.6
redis==5.0.8
redis==5.2.1
markdown-it-py==3.0.0
fasttext-predict==0.9.2.4
tomli==2.2.1; python_version < '3.11'
msgspec==0.19.0
typer-slim==0.15.3
typer-slim==0.16.0
isodate==0.7.2

View file

@ -21,7 +21,7 @@ log: logging.Logger = logging.getLogger("searx.answerers")
@dataclass
class AnswererInfo:
"""Object that holds informations about an answerer, these infos are shown
"""Object that holds information about an answerer, these infos are shown
to the user in the Preferences menu.
To be able to translate the information into other languages, the text must
@ -53,7 +53,7 @@ class Answerer(abc.ABC):
@abc.abstractmethod
def info(self) -> AnswererInfo:
"""Informations about the *answerer*, see :py:obj:`AnswererInfo`."""
"""Information about the *answerer*, see :py:obj:`AnswererInfo`."""
class ModuleAnswerer(Answerer):

View file

@ -149,6 +149,21 @@ def mwmbl(query, _lang):
return [result for result in results if not result.startswith("go: ") and not result.startswith("search: ")]
def naver(query, _lang):
# Naver search autocompleter
url = f"https://ac.search.naver.com/nx/ac?{urlencode({'q': query, 'r_format': 'json', 'st': 0})}"
response = get(url)
results = []
if response.ok:
data = response.json()
if data.get('items'):
for item in data['items'][0]:
results.append(item[0])
return results
def qihu360search(query, _lang):
# 360Search search autocompleter
url = f"https://sug.so.360.cn/suggest?{urlencode({'format': 'json', 'word': query})}"
@ -300,6 +315,7 @@ backends = {
'duckduckgo': duckduckgo,
'google': google_complete,
'mwmbl': mwmbl,
'naver': naver,
'quark': quark,
'qwant': qwant,
'seznam': seznam,

View file

@ -319,9 +319,9 @@ def dict_deepupdate(base_dict: dict, upd_dict: dict, names=None):
"""
# pylint: disable=too-many-branches
if not isinstance(base_dict, dict):
raise TypeError("argument 'base_dict' is not a ditionary type")
raise TypeError("argument 'base_dict' is not a dictionary type")
if not isinstance(upd_dict, dict):
raise TypeError("argument 'upd_dict' is not a ditionary type")
raise TypeError("argument 'upd_dict' is not a dictionary type")
if names is None:
names = []

View file

@ -42,7 +42,7 @@ class ExpireCacheCfg(msgspec.Struct): # pylint: disable=too-few-public-methods
DB will be created in `/tmp/sxng_cache_{self.name}.db`"""
MAX_VALUE_LEN: int = 1024 * 10
"""Max lenght of a *serialized* value."""
"""Max length of a *serialized* value."""
MAXHOLD_TIME: int = 60 * 60 * 24 * 7 # 7 days
"""Hold time (default in sec.), after which a value is removed from the cache."""
@ -80,7 +80,7 @@ class ExpireCacheCfg(msgspec.Struct): # pylint: disable=too-few-public-methods
@dataclasses.dataclass
class ExpireCacheStats:
"""Dataclass wich provides information on the status of the cache."""
"""Dataclass which provides information on the status of the cache."""
cached_items: dict[str, list[tuple[str, typing.Any, int]]]
"""Values in the cache mapped by context name.

View file

@ -4,29 +4,65 @@
make data.all
"""
from __future__ import annotations
__all__ = [
'ENGINE_TRAITS',
'CURRENCIES',
'USER_AGENTS',
'EXTERNAL_URLS',
'WIKIDATA_UNITS',
'EXTERNAL_BANGS',
'OSM_KEYS_TAGS',
'ENGINE_DESCRIPTIONS',
'LOCALES',
'ahmia_blacklist_loader',
]
__all__ = ["ahmia_blacklist_loader"]
import json
from pathlib import Path
import typing
data_dir = Path(__file__).parent
from .core import log, data_dir
from .currencies import CurrenciesDB
CURRENCIES: CurrenciesDB
USER_AGENTS: dict[str, typing.Any]
EXTERNAL_URLS: dict[str, typing.Any]
WIKIDATA_UNITS: dict[str, typing.Any]
EXTERNAL_BANGS: dict[str, typing.Any]
OSM_KEYS_TAGS: dict[str, typing.Any]
ENGINE_DESCRIPTIONS: dict[str, typing.Any]
ENGINE_TRAITS: dict[str, typing.Any]
LOCALES: dict[str, typing.Any]
lazy_globals = {
"CURRENCIES": CurrenciesDB(),
"USER_AGENTS": None,
"EXTERNAL_URLS": None,
"WIKIDATA_UNITS": None,
"EXTERNAL_BANGS": None,
"OSM_KEYS_TAGS": None,
"ENGINE_DESCRIPTIONS": None,
"ENGINE_TRAITS": None,
"LOCALES": None,
}
data_json_files = {
"USER_AGENTS": "useragents.json",
"EXTERNAL_URLS": "external_urls.json",
"WIKIDATA_UNITS": "wikidata_units.json",
"EXTERNAL_BANGS": "external_bangs.json",
"OSM_KEYS_TAGS": "osm_keys_tags.json",
"ENGINE_DESCRIPTIONS": "engine_descriptions.json",
"ENGINE_TRAITS": "engine_traits.json",
"LOCALES": "locales.json",
}
def _load(filename):
with open(data_dir / filename, encoding='utf-8') as f:
return json.load(f)
def __getattr__(name):
# lazy init of the global objects
if name not in lazy_globals:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
data = lazy_globals[name]
if data is not None:
return data
log.debug("init searx.data.%s", name)
with open(data_dir / data_json_files[name], encoding='utf-8') as f:
lazy_globals[name] = json.load(f)
return lazy_globals[name]
def ahmia_blacklist_loader():
@ -40,14 +76,3 @@ def ahmia_blacklist_loader():
"""
with open(data_dir / 'ahmia_blacklist.txt', encoding='utf-8') as f:
return f.read().split()
CURRENCIES = _load('currencies.json')
USER_AGENTS = _load('useragents.json')
EXTERNAL_URLS = _load('external_urls.json')
WIKIDATA_UNITS = _load('wikidata_units.json')
EXTERNAL_BANGS = _load('external_bangs.json')
OSM_KEYS_TAGS = _load('osm_keys_tags.json')
ENGINE_DESCRIPTIONS = _load('engine_descriptions.json')
ENGINE_TRAITS = _load('engine_traits.json')
LOCALES = _load('locales.json')

File diff suppressed because it is too large Load diff

29
searx/data/core.py Normal file
View file

@ -0,0 +1,29 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=missing-module-docstring
from __future__ import annotations
import pathlib
from searx import logger
from searx.cache import ExpireCacheCfg, ExpireCacheSQLite
log = logger.getChild("data")
data_dir = pathlib.Path(__file__).parent
_DATA_CACHE: ExpireCacheSQLite = None # type: ignore
def get_cache():
global _DATA_CACHE # pylint: disable=global-statement
if _DATA_CACHE is None:
_DATA_CACHE = ExpireCacheSQLite.build_cache(
ExpireCacheCfg(
name="DATA_CACHE",
# MAX_VALUE_LEN=1024 * 200, # max. 200kB length for a *serialized* value.
# MAXHOLD_TIME=60 * 60 * 24 * 7 * 4, # 4 weeks
)
)
return _DATA_CACHE

View file

@ -1428,7 +1428,7 @@
},
"CZK": {
"ar": "كرونة تشيكية",
"bg": "крони",
"bg": "Чешка крона",
"bn": "চেক কোরুনা",
"ca": "corona txeca",
"cs": "koruna česká",
@ -2687,7 +2687,7 @@
"uk": "Йорданський динар"
},
"JPY": {
"af": "Jen",
"af": "jen",
"ar": "ين ياباني",
"bg": "японска йена",
"bn": "জাপানি ইয়েন",
@ -4329,7 +4329,7 @@
"PLN": {
"af": "Złoty",
"ar": "زواتي بولندي",
"bg": "Полска злотаПолска злота",
"bg": "Полска злота",
"ca": "złoty",
"cs": "zlotý",
"da": "zloty",
@ -4375,7 +4375,7 @@
"PLZ": {
"af": "Złoty",
"ar": "زواتي بولندي",
"bg": "Полска злотаПолска злота",
"bg": "Полска злота",
"ca": "złoty",
"cs": "zlotý",
"da": "zloty",
@ -5253,6 +5253,7 @@
"ja": "ソモニ",
"ko": "타지키스탄 소모니",
"lt": "Somonis",
"lv": "somoni",
"ms": "Somoni",
"nl": "Tadzjiekse somoni",
"pa": "ਤਾਜਿਕਿਸਤਾਨੀ ਸੋਮੋਨੀ",
@ -5880,6 +5881,10 @@
"tt": "самоа таласы",
"uk": "Самоанська тала"
},
"XAD": {
"en": "Arab accounting dinar",
"fr": "dinar arabe"
},
"XAF": {
"ar": "فرنك وسط إفريقي",
"bg": "Централноафрикански CFA франк",
@ -6374,6 +6379,7 @@
"$usd": "USD",
"1000 lira": "LBP",
"100ドル紙幣": "NIO",
"1億ベネズエラ・ボリバル": "VES",
"2019 zimbabwean dollar": "ZWL",
"5th zimbabwean dollar": "ZWL",
"A$": "AUD",
@ -6510,6 +6516,7 @@
"Z$": "ZWL",
"ZK": "ZMW",
"a$": "AUD",
"aad": "XAD",
"abd doları": "USD",
"adb unit of account": "XUA",
"ae92 0530 0000 1514 1185 002": "AED",
@ -6609,6 +6616,7 @@
"aoa": "AOA",
"apvienotās karalistes sterliņu mārciņa": "GBP",
"ar": "MGA",
"arab accounting dinar": "XAD",
"arabiemiraattien dirhami": "AED",
"arany mint befektetés": "XAU",
"arg$": "ARS",
@ -7437,6 +7445,7 @@
"dinar algierski": "DZD",
"dinar aljazair": "DZD",
"dinar alxeriano": "DZD",
"dinar arabe": "XAD",
"dinar argelino": "DZD",
"dinar bahrain": "BHD",
"dinar bahraini": "BHD",
@ -7457,6 +7466,7 @@
"dinar bhairéin": "BHD",
"dinar chuáit": "KWD",
"dinar coaitiano": "KWD",
"dinar comptable arabe": "XAD",
"dinar couaitiano": "KWD",
"dinar covaitiano": "KWD",
"dinar coveiteano": "KWD",
@ -9161,7 +9171,6 @@
"jordán dinár": "JOD",
"jordánsky dinár": "JOD",
"jordánský dinár": "JOD",
"jpy": "JPY",
"juan": "CNY",
"juanis": "CNY",
"juaņa": "CNY",
@ -9812,7 +9821,6 @@
"livre de sainte hélène": "SHP",
"livre des îles falkland": "FKP",
"livre des îles malouines": "FKP",
"livre egyptienne": "EGP",
"livre égyptienne": "EGP",
"livre libanaise": "LBP",
"livre soudanaise": "SDG",
@ -11918,6 +11926,8 @@
"tadžikistani somoni": "TJS",
"tadžikistanin somoni": "TJS",
"tadžikistanski somoni": "TJS",
"tadžikistānas somoni": "TJS",
"tadžiku somoni": "TJS",
"taĝika somonio": "TJS",
"tai baat": "THB",
"tailando batas": "THB",
@ -13364,7 +13374,6 @@
],
"крона чеська": "CZK",
"крона швеции": "SEK",
"крони": "CZK",
"куба писысы": "CUP",
"кубански пезос": "CUP",
"кубански песо": "CUP",
@ -13642,10 +13651,6 @@
"PLZ",
"PLN"
],
"полска злотаполска злота": [
"PLZ",
"PLN"
],
"польский злотый": [
"PLZ",
"PLN"
@ -15675,6 +15680,7 @@
"チュニジア・ディナール": "TND",
"チリの通貨": "CLP",
"チリ・ペソ": "CLP",
"デジタルルピー": "INR",
"デンマーククローネ": "DKK",
"デンマーク・クローネ": "DKK",
"テンゲ": "KZT",

55
searx/data/currencies.py Normal file
View file

@ -0,0 +1,55 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Simple implementation to store currencies data in a SQL database."""
from __future__ import annotations
__all__ = ["CurrenciesDB"]
import json
import pathlib
from .core import get_cache, log
class CurrenciesDB:
# pylint: disable=missing-class-docstring
ctx_names = "data_currencies_names"
ctx_iso4217 = "data_currencies_iso4217"
json_file = pathlib.Path(__file__).parent / "currencies.json"
def __init__(self):
self.cache = get_cache()
def init(self):
if self.cache.properties("currencies loaded") != "OK":
self.load()
self.cache.properties.set("currencies loaded", "OK")
# F I X M E:
# do we need a maintenance .. rember: database is stored
# in /tmp and will be rebuild during the reboot anyway
def load(self):
log.debug("init searx.data.CURRENCIES")
with open(self.json_file, encoding="utf-8") as f:
data_dict = json.load(f)
for key, value in data_dict["names"].items():
self.cache.set(key=key, value=value, ctx=self.ctx_names, expire=None)
for key, value in data_dict["iso4217"].items():
self.cache.set(key=key, value=value, ctx=self.ctx_iso4217, expire=None)
def name_to_iso4217(self, name):
self.init()
ret_val = self.cache.get(key=name, default=name, ctx=self.ctx_names)
if isinstance(ret_val, list):
# if more alternatives, use the last in the list
ret_val = ret_val[-1]
return ret_val
def iso4217_to_name(self, iso4217, language):
self.init()
iso4217_languages: dict = self.cache.get(key=iso4217, default={}, ctx=self.ctx_iso4217)
return iso4217_languages.get(language, iso4217)

File diff suppressed because one or more lines are too long

View file

@ -1684,8 +1684,10 @@
"custom": {
"ui_lang": {
"bg": "bg",
"br": "br",
"ca": "ca",
"cs": "cs",
"cy": "cy",
"da": "da",
"de-DE": "de-de",
"el": "el",
@ -1695,9 +1697,11 @@
"en-US": "en-us",
"es": "es",
"et": "et",
"eu": "eu",
"fi-FI": "fi-fi",
"fr-CA": "fr-ca",
"fr-FR": "fr-fr",
"gl": "gl",
"hr": "hr",
"hu": "hu",
"id": "id",
@ -1786,8 +1790,10 @@
"custom": {
"ui_lang": {
"bg": "bg",
"br": "br",
"ca": "ca",
"cs": "cs",
"cy": "cy",
"da": "da",
"de-DE": "de-de",
"el": "el",
@ -1797,9 +1803,11 @@
"en-US": "en-us",
"es": "es",
"et": "et",
"eu": "eu",
"fi-FI": "fi-fi",
"fr-CA": "fr-ca",
"fr-FR": "fr-fr",
"gl": "gl",
"hr": "hr",
"hu": "hu",
"id": "id",
@ -1888,8 +1896,10 @@
"custom": {
"ui_lang": {
"bg": "bg",
"br": "br",
"ca": "ca",
"cs": "cs",
"cy": "cy",
"da": "da",
"de-DE": "de-de",
"el": "el",
@ -1899,9 +1909,11 @@
"en-US": "en-us",
"es": "es",
"et": "et",
"eu": "eu",
"fi-FI": "fi-fi",
"fr-CA": "fr-ca",
"fr-FR": "fr-fr",
"gl": "gl",
"hr": "hr",
"hu": "hu",
"id": "id",
@ -1990,8 +2002,10 @@
"custom": {
"ui_lang": {
"bg": "bg",
"br": "br",
"ca": "ca",
"cs": "cs",
"cy": "cy",
"da": "da",
"de-DE": "de-de",
"el": "el",
@ -2001,9 +2015,11 @@
"en-US": "en-us",
"es": "es",
"et": "et",
"eu": "eu",
"fi-FI": "fi-fi",
"fr-CA": "fr-ca",
"fr-FR": "fr-fr",
"gl": "gl",
"hr": "hr",
"hu": "hu",
"id": "id",
@ -7100,6 +7116,7 @@
"BY",
"BZ",
"CA",
"CC",
"CD",
"CF",
"CG",
@ -7364,7 +7381,6 @@
"ko": "korean",
"ks": "kashmiri",
"ku": "kurdish",
"kw": "cornish",
"la": "latin",
"lb": "luxembourgish",
"ln": "lingala",

View file

@ -5,7 +5,7 @@
],
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
"versions": [
"138.0",
"137.0"
"139.0",
"138.0"
]
}

View file

@ -4199,11 +4199,6 @@
"symbol": "St",
"to_si_factor": 13450.0
},
"Q235729": {
"si_name": "Q11574",
"symbol": "y (365 days)",
"to_si_factor": 31536000.0
},
"Q23823681": {
"si_name": "Q25236",
"symbol": "TW",
@ -6605,14 +6600,14 @@
"to_si_factor": null
},
"Q68725821": {
"si_name": null,
"si_name": "Q11579",
"symbol": "°Rø",
"to_si_factor": null
"to_si_factor": 1.90476190476
},
"Q68726230": {
"si_name": null,
"si_name": "Q11579",
"symbol": "°De",
"to_si_factor": null
"to_si_factor": 0.66667
},
"Q68726625": {
"si_name": null,

View file

@ -79,7 +79,7 @@ class EngineCache:
<searx.cache.ExpireCacheSQLite>`).
In the :origin:`searx/engines/demo_offline.py` engine you can find an
exemplary implementation of such a cache other exaples are implemeted
exemplary implementation of such a cache other examples are implemented
in:
- :origin:`searx/engines/radio_browser.py`

View file

@ -156,7 +156,7 @@ def parse_image_item(item):
def parse_video_item(item):
# in video items, the title is more or less a "content description", we try
# to reduce the lenght of the title ..
# to reduce the length of the title ..
title = item["title"]
content = ""

View file

@ -51,6 +51,9 @@ def request(query, params):
if netloc == main_wiki:
eng_lang: str = traits.get_language(sxng_lang, 'English') # type: ignore
query += ' (' + eng_lang + ')'
# wiki.archlinux.org is protected by anubis
# - https://github.com/searxng/searxng/issues/4646#issuecomment-2817848019
params['headers']['User-Agent'] = "SearXNG"
elif netloc == 'wiki.archlinuxcn.org':
base_url = 'https://' + netloc + '/wzh/index.php?'

View file

@ -3,6 +3,7 @@
"""
import json
from searx.result_types import EngineResults
# about
about = {
@ -28,13 +29,15 @@ def request(_query, params):
return params
def response(resp):
def response(resp) -> EngineResults:
res = EngineResults()
# remove first and last lines to get only json
json_resp = resp.text[resp.text.find('\n') + 1 : resp.text.rfind('\n') - 2]
try:
conversion_rate = float(json.loads(json_resp)["to"][0]["mid"])
except IndexError:
return []
return res
answer = '{0} {1} = {2} {3}, 1 {1} ({5}) = {4} {3} ({6})'.format(
resp.search_params['amount'],
resp.search_params['from'],
@ -46,5 +49,5 @@ def response(resp):
)
url = f"https://duckduckgo.com/?q={resp.search_params['from']}+to+{resp.search_params['to']}"
return [{"answer": answer, "url": url}]
res.add(res.types.Answer(answer=answer, url=url))
return res

View file

@ -58,19 +58,21 @@ paging = True
time_range_support = True
safesearch = True # user can't select but the results are filtered
url = "https://html.duckduckgo.com/html"
url = "https://html.duckduckgo.com/html/"
time_range_dict = {'day': 'd', 'week': 'w', 'month': 'm', 'year': 'y'}
form_data = {'v': 'l', 'api': 'd.js', 'o': 'json'}
CACHE: EngineCache
_CACHE: EngineCache = None # type: ignore
"""Persistent (SQLite) key/value cache that deletes its values after ``expire``
seconds."""
def init(_): # pylint: disable=unused-argument
global CACHE # pylint: disable=global-statement
CACHE = EngineCache("duckduckgo") # type:ignore
def get_cache():
global _CACHE # pylint: disable=global-statement
if _CACHE is None:
_CACHE = EngineCache("duckduckgo") # type:ignore
return _CACHE
def get_vqd(query: str, region: str, force_request: bool = False) -> str:
@ -105,8 +107,9 @@ def get_vqd(query: str, region: str, force_request: bool = False) -> str:
seems the block list is a sliding window: to get my IP rid from the bot list
I had to cool down my IP for 1h (send no requests from that IP to DDG).
"""
key = CACHE.secret_hash(f"{query}//{region}")
value = CACHE.get(key=key)
cache = get_cache()
key = cache.secret_hash(f"{query}//{region}")
value = cache.get(key=key)
if value is not None and not force_request:
logger.debug("vqd: re-use cached value: %s", value)
return value
@ -124,15 +127,16 @@ def get_vqd(query: str, region: str, force_request: bool = False) -> str:
logger.error("vqd: got HTTP %s from duckduckgo.com", resp.status_code)
if value:
CACHE.set(key=key, value=value)
cache.set(key=key, value=value)
else:
logger.error("vqd value from duckduckgo.com ", resp.status_code)
return value
def set_vqd(query: str, region: str, value: str):
key = CACHE.secret_hash(f"{query}//{region}")
CACHE.set(key=key, value=value, expire=3600)
cache = get_cache()
key = cache.secret_hash(f"{query}//{region}")
cache.set(key=key, value=value, expire=3600)
def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'):
@ -244,7 +248,6 @@ def quote_ddg_bangs(query):
def request(query, params):
query = quote_ddg_bangs(query)
if len(query) >= 500:
@ -252,93 +255,79 @@ def request(query, params):
params["url"] = None
return
# Advanced search syntax ends in CAPTCHA
# https://duckduckgo.com/duckduckgo-help-pages/results/syntax/
query = " ".join(
[
x.removeprefix("site:").removeprefix("intitle:").removeprefix("inurl:").removeprefix("filetype:")
for x in query.split()
]
)
eng_region: str = traits.get_region(params['searxng_locale'], traits.all_locale) # type: ignore
if eng_region == "wt-wt":
# https://html.duckduckgo.com/html sets an empty value for "all".
eng_region = ""
params['data']['kl'] = eng_region
params['cookies']['kl'] = eng_region
# Note: The API is reverse-engineered from DuckDuckGo's HTML webpage
# (https://html.duckduckgo.com/html/) and may be subject to additional bot detection mechanisms
# and breaking changes in the future.
#
# The params['data'] dictionary can have the following key parameters, in this order:
# - q (str): Search query string
# - b (str): Beginning parameter - empty string for first page requests
# - s (int): Search offset for pagination
# - nextParams (str): Continuation parameters from previous page response, typically empty
# - v (str): Typically 'l' for subsequent pages
# - o (str): Output format, typically 'json'
# - dc (int): Display count - value equal to offset (s) + 1
# - api (str): API endpoint identifier, typically 'd.js'
# - vqd (str): Validation query digest
# - kl (str): Keyboard language/region code (e.g., 'en-us')
# - df (str): Time filter, maps to values like 'd' (day), 'w' (week), 'm' (month), 'y' (year)
# eng_lang = get_ddg_lang(traits, params['searxng_locale'])
params['url'] = url
params['method'] = 'POST'
params['data']['q'] = query
# The API is not documented, so we do some reverse engineering and emulate
# what https://html.duckduckgo.com/html does when you press "next Page" link
# again and again ..
params['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
params['headers']['Sec-Fetch-Dest'] = "document"
params['headers']['Sec-Fetch-Mode'] = "navigate" # at least this one is used by ddg's bot detection
params['headers']['Sec-Fetch-Site'] = "same-origin"
params['headers']['Sec-Fetch-User'] = "?1"
# Form of the initial search page does have empty values in the form
if params['pageno'] == 1:
params['data']['b'] = ""
params['data']['df'] = ''
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']]
params['cookies']['df'] = time_range_dict[params['time_range']]
if params['pageno'] == 2:
# second page does have an offset of 20
offset = (params['pageno'] - 1) * 20
elif params['pageno'] >= 2:
offset = 10 + (params['pageno'] - 2) * 15 # Page 2 = 10, Page 3+ = 10 + n*15
params['data']['s'] = offset
params['data']['dc'] = offset + 1
elif params['pageno'] > 2:
# third and following pages do have an offset of 20 + n*50
offset = 20 + (params['pageno'] - 2) * 50
params['data']['s'] = offset
params['data']['dc'] = offset + 1
if params['pageno'] > 1:
# initial page does not have these additional data in the input form
params['data']['o'] = form_data.get('o', 'json')
params['data']['api'] = form_data.get('api', 'd.js')
params['data']['nextParams'] = form_data.get('nextParams', '')
params['data']['v'] = form_data.get('v', 'l')
params['headers']['Referer'] = url
params['data']['o'] = form_data.get('o', 'json')
params['data']['dc'] = offset + 1
params['data']['api'] = form_data.get('api', 'd.js')
# vqd is required to request other pages after the first one
vqd = get_vqd(query, eng_region, force_request=False)
# Certain conditions must be met in order to call up one of the
# following pages ...
if vqd:
params['data']['vqd'] = vqd # follow up pages / requests needs a vqd argument
params['data']['vqd'] = vqd
else:
# Don't try to call follow up pages without a vqd value. DDG
# recognizes this as a request from a bot. This lowers the
# Don't try to call follow up pages without a vqd value.
# DDG recognizes this as a request from a bot. This lowers the
# reputation of the SearXNG IP and DDG starts to activate CAPTCHAs.
params["url"] = None
return
if params['searxng_locale'].startswith("zh"):
# Some locales (at least China) do not have a "next page" button and ddg
# Some locales (at least China) do not have a "next page" button and DDG
# will return a HTTP/2 403 Forbidden for a request of such a page.
params["url"] = None
return
# Put empty kl in form data if language/region set to all
if eng_region == "wt-wt":
params['data']['kl'] = ""
else:
params['data']['kl'] = eng_region
params['data']['df'] = ''
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']]
params['cookies']['df'] = time_range_dict[params['time_range']]
params['cookies']['kl'] = eng_region
params['url'] = url
params['method'] = 'POST'
params['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
params['headers']['Referer'] = url
params['headers']['Sec-Fetch-Dest'] = "document"
params['headers']['Sec-Fetch-Mode'] = "navigate" # at least this one is used by ddg's bot detection
params['headers']['Sec-Fetch-Site'] = "same-origin"
params['headers']['Sec-Fetch-User'] = "?1"
logger.debug("param headers: %s", params['headers'])
logger.debug("param data: %s", params['data'])
logger.debug("param cookies: %s", params['cookies'])
@ -383,8 +372,9 @@ def response(resp) -> EngineResults:
continue
item["title"] = extract_text(title)
item["url"] = eval_xpath(div_result, './/h2/a/@href')[0]
item["content"] = extract_text(eval_xpath(div_result, './/a[contains(@class, "result__snippet")]')[0])
item["content"] = extract_text(
eval_xpath_getindex(div_result, './/a[contains(@class, "result__snippet")]', 0, [])
)
results.append(item)
zero_click_info_xpath = '//div[@id="zero_click_abstract"]'

View file

@ -1,6 +1,13 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Invidious (Videos)
If you want to use invidious with SearXNG you should setup one locally.
No public instance offer a public API now
- https://github.com/searxng/searxng/issues/2722#issuecomment-2884993248
"""
from __future__ import annotations
import time
import random
@ -13,7 +20,7 @@ from searx.utils import humanize_number
about = {
"website": 'https://api.invidious.io/',
"wikidata_id": 'Q79343316',
"official_api_documentation": 'https://github.com/iv-org/documentation/blob/master/API.md',
"official_api_documentation": 'https://docs.invidious.io/api/',
"use_official_api": True,
"require_api_key": False,
"results": 'JSON',
@ -25,7 +32,12 @@ paging = True
time_range_support = True
# base_url can be overwritten by a list of URLs in the settings.yml
base_url = 'https://vid.puffyan.us'
base_url: list | str = []
def init(_):
if not base_url:
raise ValueError("missing invidious base_url")
def request(query, params):

View file

@ -1,7 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Material Icons (images)
"""
"""Material Icons (icons)"""
import re
from json import loads
@ -14,6 +12,8 @@ about = {
"require_api_key": False,
"results": 'JSON',
}
categories = ['images', 'icons']
search_url = "https://fonts.google.com/metadata/icons?key=material_symbols&incomplete=true"
result_url = "https://fonts.google.com/icons?icon.query={query}&selected=Material+Symbols+Outlined:{icon_name}:FILL@0{fill};wght@400;GRAD@0;opsz@24" # pylint: disable=line-too-long
img_src_url = "https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/{icon_name}/{svg_type}/24px.svg"
@ -46,7 +46,7 @@ def response(resp):
continue
tags = [tag.title() for tag in result["tags"]]
categories = [category.title() for category in result["categories"]]
icon_categories = [category.title() for category in result["categories"]]
results.append(
{
@ -54,7 +54,7 @@ def response(resp):
'url': result_url.format(icon_name=result["name"], query=result["name"], fill=0 if outlined else 1),
'img_src': img_src_url.format(icon_name=result["name"], svg_type=svg_type),
'title': result["name"].replace("_", "").title(),
'content': ", ".join(tags) + " / " + ", ".join(categories),
'content': ", ".join(tags) + " / " + ", ".join(icon_categories),
}
)

210
searx/engines/naver.py Normal file
View file

@ -0,0 +1,210 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=line-too-long
"""Naver for SearXNG"""
from urllib.parse import urlencode
from lxml import html
from searx.exceptions import SearxEngineAPIException, SearxEngineXPathException
from searx.result_types import EngineResults, MainResult
from searx.utils import (
eval_xpath_getindex,
eval_xpath_list,
eval_xpath,
extract_text,
extr,
html_to_text,
parse_duration_string,
js_variable_to_python,
)
# engine metadata
about = {
"website": "https://search.naver.com",
"wikidata_id": "Q485639",
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "ko",
}
categories = []
paging = True
time_range_support = True
time_range_dict = {"day": "1d", "week": "1w", "month": "1m", "year": "1y"}
base_url = "https://search.naver.com"
naver_category = "general"
"""Naver supports general, images, news, videos search.
- ``general``: search for general
- ``images``: search for images
- ``news``: search for news
- ``videos``: search for videos
"""
# Naver cannot set the number of results on one page, set default value for paging
naver_category_dict = {
"general": {
"start": 15,
"where": "web",
},
"images": {
"start": 50,
"where": "image",
},
"news": {
"start": 10,
"where": "news",
},
"videos": {
"start": 48,
"where": "video",
},
}
def init(_):
if naver_category not in ('general', 'images', 'news', 'videos'):
raise SearxEngineAPIException(f"Unsupported category: {naver_category}")
def request(query, params):
query_params = {
"query": query,
}
if naver_category in naver_category_dict:
query_params["start"] = (params["pageno"] - 1) * naver_category_dict[naver_category]["start"] + 1
query_params["where"] = naver_category_dict[naver_category]["where"]
if params["time_range"] in time_range_dict:
query_params["nso"] = f"p:{time_range_dict[params['time_range']]}"
params["url"] = f"{base_url}/search.naver?{urlencode(query_params)}"
return params
def response(resp) -> EngineResults:
parsers = {'general': parse_general, 'images': parse_images, 'news': parse_news, 'videos': parse_videos}
return parsers[naver_category](resp.text)
def parse_general(data):
results = EngineResults()
dom = html.fromstring(data)
for item in eval_xpath_list(dom, "//ul[contains(@class, 'lst_total')]/li[contains(@class, 'bx')]"):
thumbnail = None
try:
thumbnail = eval_xpath_getindex(item, ".//div[contains(@class, 'thumb_single')]//img/@data-lazysrc", 0)
except (ValueError, TypeError, SearxEngineXPathException):
pass
results.add(
MainResult(
title=extract_text(eval_xpath(item, ".//a[contains(@class, 'link_tit')]")),
url=eval_xpath_getindex(item, ".//a[contains(@class, 'link_tit')]/@href", 0),
content=extract_text(
eval_xpath(item, ".//div[contains(@class, 'total_dsc_wrap')]//a[contains(@class, 'api_txt_lines')]")
),
thumbnail=thumbnail,
)
)
return results
def parse_images(data):
results = []
match = extr(data, '<script>var imageSearchTabData=', '</script>')
if match:
json = js_variable_to_python(match.strip())
items = json.get('content', {}).get('items', [])
for item in items:
results.append(
{
"template": "images.html",
"url": item.get('link'),
"thumbnail_src": item.get('thumb'),
"img_src": item.get('originalUrl'),
"title": html_to_text(item.get('title')),
"source": item.get('source'),
"resolution": f"{item.get('orgWidth')} x {item.get('orgHeight')}",
}
)
return results
def parse_news(data):
results = EngineResults()
dom = html.fromstring(data)
for item in eval_xpath_list(
dom, "//div[contains(@class, 'sds-comps-base-layout') and contains(@class, 'sds-comps-full-layout')]"
):
title = extract_text(eval_xpath(item, ".//span[contains(@class, 'sds-comps-text-type-headline1')]/text()"))
url = eval_xpath_getindex(item, ".//a[@href and @nocr='1']/@href", 0)
content = extract_text(eval_xpath(item, ".//span[contains(@class, 'sds-comps-text-type-body1')]"))
thumbnail = None
try:
thumbnail = eval_xpath_getindex(
item,
".//div[contains(@class, 'sds-comps-image') and contains(@class, 'sds-rego-thumb-overlay')]//img[@src]/@src",
0,
)
except (ValueError, TypeError, SearxEngineXPathException):
pass
if title and content and url:
results.add(
MainResult(
title=title,
url=url,
content=content,
thumbnail=thumbnail,
)
)
return results
def parse_videos(data):
results = []
dom = html.fromstring(data)
for item in eval_xpath_list(dom, "//li[contains(@class, 'video_item')]"):
thumbnail = None
try:
thumbnail = eval_xpath_getindex(item, ".//img[contains(@class, 'thumb')]/@src", 0)
except (ValueError, TypeError, SearxEngineXPathException):
pass
length = None
try:
length = parse_duration_string(extract_text(eval_xpath(item, ".//span[contains(@class, 'time')]")))
except (ValueError, TypeError):
pass
results.append(
{
"template": "videos.html",
"title": extract_text(eval_xpath(item, ".//a[contains(@class, 'info_title')]")),
"url": eval_xpath_getindex(item, ".//a[contains(@class, 'info_title')]/@href", 0),
"thumbnail": thumbnail,
'length': length,
}
)
return results

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Pinterest (images)
"""
"""Pinterest (images)"""
from json import dumps
@ -28,6 +27,11 @@ def request(query, params):
'context': {},
}
params['url'] = f"{base_url}/resource/BaseSearchResource/get/?data={dumps(args)}"
params['headers'] = {
'X-Pinterest-AppState': 'active',
'X-Pinterest-Source-Url': '/ideas/',
'X-Pinterest-PWS-Handler': 'www/ideas.js',
}
return params

View file

@ -137,19 +137,20 @@ def _get_request_id(query, params):
if l.territory:
headers['Accept-Language'] = f"{l.language}-{l.territory},{l.language};" "q=0.9,*;" "q=0.5"
resp_text = get(url, headers=headers).text # type: ignore
resp = get(url, headers=headers)
for line in resp_text.split("\n"):
for line in resp.text.split("\n"):
if "window.searchId = " in line:
return line.split("= ")[1][:-1].replace('"', "")
return line.split("= ")[1][:-1].replace('"', ""), resp.cookies
return None
raise RuntimeError("Couldn't find any request id for presearch")
def request(query, params):
request_id = _get_request_id(query, params)
request_id, cookies = _get_request_id(query, params)
params["headers"]["Accept"] = "application/json"
params["url"] = f"{base_url}/results?id={request_id}"
params["cookies"] = cookies
return params

View file

@ -11,7 +11,7 @@ about = {
"require_api_key": False,
"results": 'JSON',
}
categories = ['images']
categories = ['images', 'icons']
icons_list_url = 'https://cdn.selfh.st/directory/icons.json'

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Svgrepo (images)
"""Svgrepo (icons)
"""
from lxml import html
@ -14,7 +14,7 @@ about = {
}
paging = True
categories = ['images']
categories = ['images', 'icons']
base_url = "https://www.svgrepo.com"
results_xpath = "//div[@class='style_nodeListing__7Nmro']/div"

View file

@ -77,7 +77,7 @@ def response(resp):
elif item_type == 'video':
results.append(_video(item))
else:
logger.error("unknow result type: %s", item_type)
logger.error("unknown result type: %s", item_type)
return results

50
searx/engines/uxwing.py Normal file
View file

@ -0,0 +1,50 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""UXwing (images)"""
from urllib.parse import quote_plus
from lxml import html
from searx.utils import eval_xpath, eval_xpath_list, extract_text
about = {
"website": 'https://uxwing.com',
"wikidata_id": None,
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": 'HTML',
}
categories = ['images', 'icons']
base_url = "https://uxwing.com"
def request(query, params):
params['url'] = f"{base_url}/?s={quote_plus(query)}"
return params
def response(resp):
results = []
doc = html.fromstring(resp.text)
for result in eval_xpath_list(doc, "//article[starts-with(@id, 'post')]"):
classes = extract_text(eval_xpath(result, "./@class")).split(" ")
tags = []
for css_class in classes:
for prefix in ("category", "tag"):
if css_class.startswith(prefix):
tag = css_class.removeprefix(prefix)
tags.append(tag.replace("-", " ").title())
results.append(
{
'template': 'images.html',
'url': extract_text(eval_xpath(result, "./a/@href")),
'img_src': extract_text(eval_xpath(result, ".//img/@src")),
'title': extract_text(eval_xpath(result, ".//img/@alt")),
'content': ', '.join(tags),
}
)
return results

View file

@ -44,6 +44,29 @@ time_range_dict = {
'month': ('1m', 'm'),
}
region2domain = {
"CO": "co.search.yahoo.com", # Colombia
"TH": "th.search.yahoo.com", # Thailand
"VE": "ve.search.yahoo.com", # Venezuela
"CL": "cl.search.yahoo.com", # Chile
"HK": "hk.search.yahoo.com", # Hong Kong
"PE": "pe.search.yahoo.com", # Peru
"CA": "ca.search.yahoo.com", # Canada
"DE": "de.search.yahoo.com", # Germany
"FR": "fr.search.yahoo.com", # France
"TW": "tw.search.yahoo.com", # Taiwan
"GB": "uk.search.yahoo.com", # United Kingdom
"UK": "uk.search.yahoo.com",
"BR": "br.search.yahoo.com", # Brazil
"IN": "in.search.yahoo.com", # India
"ES": "espanol.search.yahoo.com", # Espanol
"PH": "ph.search.yahoo.com", # Philippines
"AR": "ar.search.yahoo.com", # Argentina
"MX": "mx.search.yahoo.com", # Mexico
"SG": "sg.search.yahoo.com", # Singapore
}
"""Map regions to domain"""
lang2domain = {
'zh_chs': 'hk.search.yahoo.com',
'zh_cht': 'tw.search.yahoo.com',
@ -65,40 +88,40 @@ lang2domain = {
yahoo_languages = {
"all": "any",
"ar": "ar",
"bg": "bg",
"cs": "cs",
"da": "da",
"de": "de",
"el": "el",
"en": "en",
"es": "es",
"et": "et",
"fi": "fi",
"fr": "fr",
"he": "he",
"hr": "hr",
"hu": "hu",
"it": "it",
"ja": "ja",
"ko": "ko",
"lt": "lt",
"lv": "lv",
"nl": "nl",
"no": "no",
"pl": "pl",
"pt": "pt",
"ro": "ro",
"ru": "ru",
"sk": "sk",
"sl": "sl",
"sv": "sv",
"th": "th",
"tr": "tr",
"zh": "zh_chs",
"ar": "ar", # Arabic
"bg": "bg", # Bulgarian
"cs": "cs", # Czech
"da": "da", # Danish
"de": "de", # German
"el": "el", # Greek
"en": "en", # English
"es": "es", # Spanish
"et": "et", # Estonian
"fi": "fi", # Finnish
"fr": "fr", # French
"he": "he", # Hebrew
"hr": "hr", # Croatian
"hu": "hu", # Hungarian
"it": "it", # Italian
"ja": "ja", # Japanese
"ko": "ko", # Korean
"lt": "lt", # Lithuanian
"lv": "lv", # Latvian
"nl": "nl", # Dutch
"no": "no", # Norwegian
"pl": "pl", # Polish
"pt": "pt", # Portuguese
"ro": "ro", # Romanian
"ru": "ru", # Russian
"sk": "sk", # Slovak
"sl": "sl", # Slovenian
"sv": "sv", # Swedish
"th": "th", # Thai
"tr": "tr", # Turkish
"zh": "zh_chs", # Chinese (Simplified)
"zh_Hans": "zh_chs",
'zh-CN': "zh_chs",
"zh_Hant": "zh_cht",
"zh_Hant": "zh_cht", # Chinese (Traditional)
"zh-HK": "zh_cht",
'zh-TW': "zh_cht",
}
@ -107,7 +130,7 @@ yahoo_languages = {
def request(query, params):
"""build request"""
lang = params["language"].split("-")[0]
lang, region = (params["language"].split("-") + [None])[:2]
lang = yahoo_languages.get(lang, "any")
offset = (params['pageno'] - 1) * 7 + 1
@ -127,9 +150,11 @@ def request(query, params):
}
)
domain = lang2domain.get(lang, '%s.search.yahoo.com' % lang)
domain = region2domain.get(region)
if not domain:
domain = lang2domain.get(lang, '%s.search.yahoo.com' % lang)
params['url'] = 'https://%s/search?%s' % (domain, args)
return params
params['domain'] = domain
def parse_url(url_string):
@ -157,14 +182,22 @@ def response(resp):
results = []
dom = html.fromstring(resp.text)
url_xpath = './/div[contains(@class,"compTitle")]/h3/a/@href'
title_xpath = './/h3//a/@aria-label'
domain = resp.search_params['domain']
if domain == "search.yahoo.com":
url_xpath = './/div[contains(@class,"compTitle")]/a/@href'
title_xpath = './/div[contains(@class,"compTitle")]/a/h3/span'
# parse results
for result in eval_xpath_list(dom, '//div[contains(@class,"algo-sr")]'):
url = eval_xpath_getindex(result, './/h3/a/@href', 0, default=None)
url = eval_xpath_getindex(result, url_xpath, 0, default=None)
if url is None:
continue
url = parse_url(url)
title = eval_xpath_getindex(result, './/h3//a/@aria-label', 0, default='')
title = eval_xpath_getindex(result, title_xpath, 0, default='')
title: str = extract_text(title)
content = eval_xpath_getindex(result, './/div[contains(@class, "compText")]', 0, default='')
content: str = extract_text(content, allow_none=True)

View file

@ -180,6 +180,8 @@ def fetch_traits(engine_traits: EngineTraits) -> None:
# pylint: disable=import-outside-toplevel, too-many-branches
import babel
import httpx
from searx.network import get # see https://github.com/searxng/searxng/issues/762
from searx.locales import language_tag
@ -191,7 +193,7 @@ def fetch_traits(engine_traits: EngineTraits) -> None:
try:
resp = get(base_url, verify=False)
except SearxException as exc:
except (SearxException, httpx.ConnectError) as exc:
print(f"ERROR: zlibrary domain '{base_url}' is seized?")
print(f" --> {exc}")
_use_old_values()

View file

@ -42,7 +42,7 @@ class SXNG_Request(flask.Request):
"""list of searx.plugins.Plugin.id (the id of the plugins)"""
preferences: "searx.preferences.Preferences"
"""The prefernces of the request."""
"""The preferences of the request."""
errors: list[str]
"""A list of errors (translated text) added by :py:obj:`searx.webapp` in

View file

@ -140,7 +140,7 @@ class FaviconCacheConfig(msgspec.Struct): # pylint: disable=too-few-public-meth
@dataclasses.dataclass
class FaviconCacheStats:
"""Dataclass wich provides information on the status of the cache."""
"""Dataclass which provides information on the status of the cache."""
favicons: int | None = None
bytes: int | None = None
@ -387,7 +387,7 @@ CREATE TABLE IF NOT EXISTS blob_map (
self.properties.set("LAST_MAINTENANCE", "") # hint: this (also) sets the m_time of the property!
# Do maintenance tasks. This can be take a little more time, to avoid
# DB locks, etablish a new DB connecton.
# DB locks, establish a new DB connection.
with self.connect() as conn:

View file

@ -24,7 +24,7 @@ LOOP = None
SSLCONTEXTS: Dict[Any, SSLContext] = {}
def shuffle_ciphers(ssl_context):
def shuffle_ciphers(ssl_context: SSLContext):
"""Shuffle httpx's default ciphers of a SSL context randomly.
From `What Is TLS Fingerprint and How to Bypass It`_
@ -41,16 +41,16 @@ def shuffle_ciphers(ssl_context):
https://www.zenrows.com/blog/what-is-tls-fingerprint#how-to-bypass-tls-fingerprinting
"""
c_list = httpx._config.DEFAULT_CIPHERS.split(':') # pylint: disable=protected-access
c_list = [cipher["name"] for cipher in ssl_context.get_ciphers()]
sc_list, c_list = c_list[:3], c_list[3:]
random.shuffle(c_list)
ssl_context.set_ciphers(":".join(sc_list + c_list))
def get_sslcontexts(proxy_url=None, cert=None, verify=True, trust_env=True, http2=False):
key = (proxy_url, cert, verify, trust_env, http2)
def get_sslcontexts(proxy_url=None, cert=None, verify=True, trust_env=True):
key = (proxy_url, cert, verify, trust_env)
if key not in SSLCONTEXTS:
SSLCONTEXTS[key] = httpx.create_ssl_context(cert, verify, trust_env, http2)
SSLCONTEXTS[key] = httpx.create_ssl_context(verify, cert, trust_env)
shuffle_ciphers(SSLCONTEXTS[key])
return SSLCONTEXTS[key]
@ -120,7 +120,7 @@ def get_transport_for_socks_proxy(verify, http2, local_address, proxy_url, limit
rdns = True
proxy_type, proxy_host, proxy_port, proxy_username, proxy_password = parse_proxy_url(proxy_url)
verify = get_sslcontexts(proxy_url, None, verify, True, http2) if verify is True else verify
verify = get_sslcontexts(proxy_url, None, verify, True) if verify is True else verify
return AsyncProxyTransportFixed(
proxy_type=proxy_type,
proxy_host=proxy_host,
@ -138,7 +138,7 @@ def get_transport_for_socks_proxy(verify, http2, local_address, proxy_url, limit
def get_transport(verify, http2, local_address, proxy_url, limit, retries):
verify = get_sslcontexts(None, None, verify, True, http2) if verify is True else verify
verify = get_sslcontexts(None, None, verify, True) if verify is True else verify
return httpx.AsyncHTTPTransport(
# pylint: disable=protected-access
verify=verify,

View file

@ -180,7 +180,7 @@ class Network:
Network._TOR_CHECK_RESULT[proxies] = result
return result
async def get_client(self, verify=None, max_redirects=None):
async def get_client(self, verify=None, max_redirects=None) -> httpx.AsyncClient:
verify = self.verify if verify is None else verify
max_redirects = self.max_redirects if max_redirects is None else max_redirects
local_address = next(self._local_addresses_cycle)
@ -269,6 +269,8 @@ class Network:
kwargs_clients = Network.extract_kwargs_clients(kwargs)
while retries >= 0: # pragma: no cover
client = await self.get_client(**kwargs_clients)
cookies = kwargs.pop("cookies", None)
client.cookies = httpx.Cookies(cookies)
try:
if stream:
response = client.stream(method, url, **kwargs)

View file

@ -8,7 +8,7 @@ class OpenMetricsFamily: # pylint: disable=too-few-public-methods
The type_hint parameter must be one of 'counter', 'gauge', 'histogram', 'summary'.
The help_hint parameter is a short string explaining the metric.
The data_info parameter is a dictionary of descriptionary parameters for the data point (e.g. request method/path).
The data parameter is a flat list of the actual data in shape of a primive type.
The data parameter is a flat list of the actual data in shape of a primitive type.
See https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md for more information.
"""

View file

@ -26,7 +26,7 @@ log: logging.Logger = logging.getLogger("searx.plugins")
@dataclass
class PluginInfo:
"""Object that holds informations about a *plugin*, these infos are shown to
"""Object that holds information about a *plugin*, these infos are shown to
the user in the Preferences menu.
To be able to translate the information into other languages, the text must
@ -85,7 +85,7 @@ class Plugin(abc.ABC):
constructor (if not already set in the subclass)."""
info: PluginInfo
"""Informations about the *plugin*, see :py:obj:`PluginInfo`."""
"""Information about the *plugin*, see :py:obj:`PluginInfo`."""
fqn: str = ""
@ -129,8 +129,8 @@ class Plugin(abc.ABC):
def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-argument
"""Initialization of the plugin, the return value decides whether this
plugin is active or not. Initialization only takes place once, at the
time the WEB application is set up. The base methode always returns
``True``, the methode can be overwritten in the inheritances,
time the WEB application is set up. The base method always returns
``True``, the method can be overwritten in the inheritances,
- ``True`` plugin is active
- ``False`` plugin is inactive

View file

@ -12,24 +12,13 @@ from .online import OnlineProcessor
parser_re = re.compile('.*?(\\d+(?:\\.\\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)', re.I)
def normalize_name(name):
def normalize_name(name: str):
name = name.strip()
name = name.lower().replace('-', ' ').rstrip('s')
name = re.sub(' +', ' ', name)
return unicodedata.normalize('NFKD', name).lower()
def name_to_iso4217(name):
name = normalize_name(name)
currency = CURRENCIES['names'].get(name, [name])
if isinstance(currency, str):
return currency
return currency[-1]
def iso4217_to_name(iso4217, language):
return CURRENCIES['iso4217'].get(iso4217, {}).get(language, iso4217)
class OnlineCurrencyProcessor(OnlineProcessor):
"""Processor class used by ``online_currency`` engines."""
@ -52,14 +41,15 @@ class OnlineCurrencyProcessor(OnlineProcessor):
amount = float(amount_str)
except ValueError:
return None
from_currency = name_to_iso4217(from_currency.strip())
to_currency = name_to_iso4217(to_currency.strip())
from_currency = CURRENCIES.name_to_iso4217(normalize_name(from_currency))
to_currency = CURRENCIES.name_to_iso4217(normalize_name(to_currency))
params['amount'] = amount
params['from'] = from_currency
params['to'] = to_currency
params['from_name'] = iso4217_to_name(from_currency, 'en')
params['to_name'] = iso4217_to_name(to_currency, 'en')
params['from_name'] = CURRENCIES.iso4217_to_name(from_currency, "en")
params['to_name'] = CURRENCIES.iso4217_to_name(to_currency, "en")
return params
def get_default_tests(self):

View file

@ -34,7 +34,7 @@ search:
# Filter results. 0: None, 1: Moderate, 2: Strict
safe_search: 0
# Existing autocomplete backends: "360search", "baidu", "brave", "dbpedia", "duckduckgo", "google", "yandex",
# "mwmbl", "seznam", "sogou", "stract", "swisscows", "quark", "qwant", "wikipedia" -
# "mwmbl", "naver", "seznam", "sogou", "stract", "swisscows", "quark", "qwant", "wikipedia" -
# leave blank to turn it off by default.
autocomplete: ""
# minimun characters to type before autocompleter starts
@ -169,18 +169,6 @@ ui:
# - image_proxy
# - query_in_title
# searx supports result proxification using an external service:
# https://github.com/asciimoo/morty uncomment below section if you have running
# morty proxy the key is base64 encoded (keep the !!binary notation)
# Note: since commit af77ec3, morty accepts a base64 encoded key.
#
# result_proxy:
# url: http://127.0.0.1:3000/
# # the key is a base64 encoded string, the YAML !!binary prefix is optional
# key: !!binary "your_morty_proxy_key"
# # [true|false] enable the "proxy" button next to each result
# proxify_results: true
# communication with search engines
#
outgoing:
@ -264,8 +252,8 @@ plugins:
#
# hostnames:
# replace:
# '(.*\.)?youtube\.com$': 'invidious.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com'
# '(.*\.)?youtube\.com$': 'yt.example.com'
# '(.*\.)?youtu\.be$': 'yt.example.com'
# '(.*\.)?reddit\.com$': 'teddit.example.com'
# '(.*\.)?redd\.it$': 'teddit.example.com'
# '(www\.)?twitter\.com$': 'nitter.example.com'
@ -282,8 +270,8 @@ plugins:
# replace: 'rewrite-hosts.yml'
#
# Content of 'rewrite-hosts.yml' (place the file in the same directory as 'settings.yml'):
# '(.*\.)?youtube\.com$': 'invidious.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com'
# '(.*\.)?youtube\.com$': 'yt.example.com'
# '(.*\.)?youtu\.be$': 'yt.example.com'
#
checker:
@ -1065,7 +1053,6 @@ engines:
- name: material icons
engine: material_icons
categories: images
shortcut: mi
disabled: true
@ -1129,6 +1116,7 @@ engines:
- name: il post
engine: il_post
shortcut: pst
disabled: true
- name: huggingface
engine: huggingface
@ -1164,16 +1152,15 @@ engines:
timeout: 6.0
disabled: true
- name: invidious
engine: invidious
# Instanes will be selected randomly, see https://api.invidious.io/ for
# instances that are stable (good uptime) and close to you.
base_url:
- https://invidious.adminforge.de
- https://inv.nadeko.net
shortcut: iv
timeout: 3.0
disabled: true
# - name: invidious
# engine: invidious
# # if you want to use invidious with SearXNG you should setup one locally
# # https://github.com/searxng/searxng/issues/2722#issuecomment-2884993248
# base_url:
# - https://invidious.example1.com
# - https://invidious.example2.com
# shortcut: iv
# timeout: 3.0
- name: ipernity
engine: ipernity
@ -1249,11 +1236,13 @@ engines:
shortcut: zlib
categories: files
timeout: 7.0
disabled: true
- name: library of congress
engine: loc
shortcut: loc
categories: images
disabled: true
- name: libretranslate
engine: libretranslate
@ -1720,6 +1709,7 @@ engines:
engine: qwant
shortcut: qw
categories: [general, web]
disabled: true
additional_tests:
rosebud: *test_rosebud
@ -2371,25 +2361,31 @@ engines:
disabled: true
- name: naver
shortcut: nvr
categories: [general, web]
engine: xpath
paging: true
search_url: https://search.naver.com/search.naver?where=webkr&sm=osp_hty&ie=UTF-8&query={query}&start={pageno}
url_xpath: //a[@class="link_tit"]/@href
title_xpath: //a[@class="link_tit"]
content_xpath: //div[@class="total_dsc_wrap"]/a
first_page_num: 1
page_size: 10
engine: naver
shortcut: nvr
disabled: true
- name: naver images
naver_category: images
categories: [images]
engine: naver
shortcut: nvri
disabled: true
- name: naver news
naver_category: news
categories: [news]
engine: naver
shortcut: nvrn
disabled: true
- name: naver videos
naver_category: videos
categories: [videos]
engine: naver
shortcut: nvrv
disabled: true
about:
website: https://www.naver.com/
wikidata_id: Q485639
official_api_documentation: https://developers.naver.com/docs/nmt/examples/
use_official_api: false
require_api_key: false
results: HTML
language: ko
- name: rubygems
shortcut: rbg
@ -2536,6 +2532,11 @@ engines:
engine: tootfinder
shortcut: toot
- name: uxwing
engine: uxwing
shortcut: ux
disabled: true
- name: voidlinux
engine: voidlinux
shortcut: void

View file

@ -230,11 +230,6 @@ SCHEMA = {
'extra_proxy_timeout': SettingsValue(int, 0),
'networks': {},
},
'result_proxy': {
'url': SettingsValue((None, str), None),
'key': SettingsBytesValue((None, bytes), None),
'proxify_results': SettingsValue(bool, False),
},
'plugins': SettingsValue(dict, {}),
'checker': {
'off_when_debug': SettingsValue(bool, True, None),

View file

@ -114,7 +114,7 @@ class SQLiteAppl(abc.ABC):
"""
SQLITE_JOURNAL_MODE = "WAL"
"""``SQLiteAppl`` applications are optimzed for WAL_ mode, its not recommend
"""``SQLiteAppl`` applications are optimized for WAL_ mode, its not recommend
to change the journal mode (see :py:obj:`SQLiteAppl.tear_down`).
.. _WAL: https://sqlite.org/wal.html
@ -145,7 +145,7 @@ class SQLiteAppl(abc.ABC):
- https://github.com/python/cpython/issues/118172
- https://github.com/python/cpython/issues/123873
The workaround for SQLite3 multithreading cache inconsistency ist to set
The workaround for SQLite3 multithreading cache inconsistency is to set
option ``cached_statements`` to ``0`` by default.
"""

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 966 B

After

Width:  |  Height:  |  Size: 8.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 726 B

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

View file

@ -1 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" width="853.677" height="146.304" viewBox="0 0 225.869 38.71"><g aria-label="SearXNG" style="line-height:1.25" font-style="normal" font-weight="400" font-size="50.8px" font-family="sans-serif" fill="#487cff" fill-opacity="1" stroke="none" stroke-width=".264583"><path d="M56.494 102.704q-1.168-1.22-3.048-2.032t-4.42-.813q-3.15 0-5.08 1.32-1.93 1.27-1.93 3.455 0 2.337 3.708 3.607l7.671 2.641q3.963 1.321 5.842 3.404 1.88 2.083 1.88 5.13 0 4.065-2.185 7.011-2.184 2.896-5.943 4.42-3.76 1.524-8.484 1.524-5.334 0-9.042-1.778-3.709-1.829-5.537-5.131-.204-.356-.204-.711 0-.356.407-.61l4.013-2.438q.356-.254.762-.254.61 0 1.118.66 1.32 1.626 2.387 2.54 1.118.864 2.693 1.321 1.625.457 4.165.457 3.2 0 5.182-1.168 1.981-1.22 1.981-3.76 0-1.27-.914-2.082-.915-.864-2.947-1.575l-7.417-2.49q-3.657-1.218-5.588-3.555-1.88-2.388-1.88-5.436 0-3.759 2.134-6.655 2.134-2.895 5.69-4.47 3.607-1.575 7.874-1.575 4.369 0 7.67 1.575 3.354 1.524 5.182 3.962.407.508.407.762t-.356.458l-4.52 2.997q-.052.05-.204.05-.305 0-1.067-.761M77.004 132.37q-3.607 0-6.401-1.472-2.794-1.474-4.318-4.115-1.524-2.693-1.524-6.198 0-4.165 1.981-7.874 2.032-3.759 5.537-5.994 3.556-2.286 7.925-2.286 5.334 0 8.484 3.15t3.15 8.686q0 1.473-.204 2.845-.101.406-.355.61-.204.152-.813.152h-17.12q-.813 0-.813 2.184 0 2.388 1.524 3.709 1.575 1.27 4.064 1.27 1.93 0 3.607-.813t3.302-2.54q.254-.254.508-.254.153 0 .66.203l3.353 1.575q.61.203.61.66 0 .254-.254.66-2.946 3.303-5.893 4.573-2.895 1.27-7.01 1.27m6.451-16.56q1.22 0 1.22-1.981 0-1.93-1.169-3.251-1.168-1.372-3.251-1.372-2.54 0-4.521 1.93-1.93 1.88-2.235 4.674zM109.411 129.374q-3.048 2.997-8.331 2.997-3.556 0-5.588-1.829t-2.032-4.775q0-3.607 2.387-5.893 2.388-2.337 5.995-3.353 3.657-1.067 7.569-1.168l1.829-.153q.965 0 1.117-.965l.153-1.067q.05-.254.05-.812 0-3.048-3.505-3.048-4.013 0-5.943 3.15-.254.355-.66.355-.305 0-.458-.051l-4.927-1.168q-.508-.102-.508-.66 0-.509.254-1.017 3.352-5.486 12.649-5.486 5.486 0 8.026 1.93 2.591 1.93 2.591 5.334 0 .457-.102 1.473l-2.54 17.78q-.05.66-.203.813-.152.102-.711.102h-5.232q-.508 0-.66-.305t-.204-1.016l.05-1.32q0-.407-.253-.407-.254 0-.813.559m2.184-9.754v-.305q0-.203-.101-.254-.102-.101-.407-.05l-1.828.152q-2.947.203-5.487 1.473t-2.54 3.912q0 1.219.864 1.98.914.712 2.438.712 1.321 0 2.49-.356 1.168-.406 2.031-1.066 1.88-1.423 2.083-2.896zM123.864 131.863q-.61 0-.915-.356-.254-.355-.152-.914l3.505-24.943q.05-.457.152-.559.153-.152.56-.152h6.044q.915 0 .712 1.067l-.356 2.286v.203q0 .355.203.355.153 0 .457-.304 1.778-1.88 3.963-2.998 2.184-1.117 3.962-1.117 1.067 0 1.575.152.508.153.457.61l-.813 5.69q-.05.558-.203.71-.101.153-.406.102-1.727-.254-3.455-.254-1.32 0-2.794.711-1.473.66-2.54 1.778-1.016 1.067-1.168 2.134l-2.083 14.834q-.101.66-.355.812-.204.153-.966.153zM176.481 130.085q.457.813.457 1.219 0 .305-.254.457-.254.102-.762.102h-7.06q-.61 0-.966-.153-.305-.152-.508-.61l-5.639-11.734q-.254-.508-.508-.508-.152 0-.559.559l-9.042 11.836q-.254.407-.61.508-.304.102-1.066.102h-5.944q-1.016 0-1.016-.66 0-.458.762-1.525l13.005-16.306q.559-.61.559-1.067 0-.356-.102-.559l-8.484-16.56q-.152-.255-.152-.509 0-.508.762-.508h7.417q.66 0 .914.153.254.152.508.66l4.928 10.363q.152.407.355.407.204 0 .508-.407l8.027-10.566q.305-.407.559-.508.304-.102.965-.102h6.553q.61 0 .61.559 0 .406-.305.914l-12.599 15.647q-.508.66-.508.914 0 .203.153.508zM218.113 94.17q.355 0 .457.202.101.153.05.56l-5.13 36.372q-.05.356-.254.457-.153.102-.559.102h-5.182q-.66 0-1.168-.813l-13.106-22.708q-.153-.254-.305-.254-.305 0-.356.56l-3.15 22.402q-.1.508-.304.66-.153.153-.711.153h-5.588q-.813 0-.712-1.118l5.08-35.814q.102-.508.204-.61.152-.152.66-.152h6.147q.508 0 .762.254.305.203.559.711l11.988 21.184q.254.406.508.406.407 0 .458-.61l2.946-21.284q.05-.407.203-.508.203-.153.66-.153zM236.44 132.37q-4.572 0-7.925-1.93t-5.131-5.435q-1.727-3.556-1.727-8.331 0-6.3 2.489-11.532 2.49-5.283 7.061-8.382 4.572-3.099 10.516-3.099 4.064 0 7.163 1.575 3.15 1.575 4.876 4.166 1.728 2.54 1.83 5.435 0 .508-.102.762-.051.203-.254.254l-6.96 1.016h-.05q-.204 0-.356-.254-.102-.254-.254-1.016-.356-2.54-1.93-4.115-1.525-1.574-4.319-1.574-3.607 0-5.994 2.641-2.337 2.642-3.455 6.807-1.117 4.115-1.117 8.586 0 4.368 1.625 6.299 1.677 1.88 4.877 1.88 3.099 0 5.233-1.728t3.15-4.216l.304-1.423q.152-.254.152-.355 0-.305-.61-.305h-6.248q-.304 0-.406-.102-.102-.152-.05-.558l.456-4.166q.051-.559.508-.559l14.53.051q.609 0 .761.203.203.153.102.66l-2.49 17.577q-.05.66-.812.66h-1.524q-.457 0-.711-.152-.204-.152-.356-.61l-.864-3.708q-.05-.254-.355-.254t-.66.407q-1.677 2.083-4.37 3.454-2.692 1.372-6.603 1.372" style="-inkscape-font-specification:&quot;Libre Franklin&quot;" transform="translate(-29.722 -93.661)" font-style="normal" font-variant="normal" font-weight="400" font-stretch="normal" font-size="50.8px" font-family="Libre Franklin" fill="#487cff" fill-opacity="1" stroke-width=".264583"/></g></svg>
<svg width="456" height="146" viewBox="0 0 456 146" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 27.375C0 12.2562 12.2495 0 27.36 0H118.56C133.671 0 145.92 12.2562 145.92 27.375V118.625C145.92 133.744 133.671 146 118.56 146H27.36C12.2495 146 0 133.744 0 118.625V27.375Z" fill="#0500E3"/>
<path d="M118.56 136.875V146H27.36V136.875H118.56ZM136.8 118.625V27.375C136.8 17.2958 128.634 9.125 118.56 9.125H27.36C17.2863 9.125 9.12 17.2958 9.12 27.375V118.625C9.12 128.704 17.2863 136.875 27.36 136.875V146L25.9528 145.964C11.4963 145.232 0 133.272 0 118.625V27.375C0 12.2562 12.2495 0 27.36 0H118.56C133.671 0 145.92 12.2562 145.92 27.375V118.625C145.92 133.744 133.671 146 118.56 146V136.875C128.634 136.875 136.8 128.704 136.8 118.625Z" fill="url(#paint0_linear_293_10)"/>
<path d="M92.91 67.2969C92.91 53.123 81.4261 41.6328 67.26 41.6328C53.0939 41.6328 41.61 53.123 41.61 67.2969C41.61 81.4707 53.0939 92.9609 67.26 92.9609C81.4261 92.9609 92.91 81.4707 92.91 67.2969ZM98.61 67.2969C98.61 84.6205 84.5741 98.6641 67.26 98.6641C49.9459 98.6641 35.91 84.6205 35.91 67.2969C35.91 49.9733 49.9459 35.9297 67.26 35.9297C84.5741 35.9297 98.61 49.9733 98.61 67.2969Z" fill="white"/>
<path d="M109.175 105.203C110.288 106.316 110.288 108.122 109.175 109.235C108.062 110.349 106.258 110.349 105.145 109.235L109.175 105.203ZM85.3977 85.4445C86.4759 84.3657 88.2032 84.3321 89.322 85.3436L89.4284 85.4445L109.175 105.203L105.145 109.235L85.3977 89.4775L85.2968 89.371C84.2859 88.2516 84.3194 86.5233 85.3977 85.4445Z" fill="white"/>
<mask id="path-5-outside-1_293_10" maskUnits="userSpaceOnUse" x="164.492" y="17.1055" width="285" height="105" fill="black">
<rect fill="white" x="164.492" y="17.1055" width="285" height="105"/>
<path d="M177.762 55.2685C175.43 55.2685 173.423 54.7176 171.738 53.6159C170.054 52.5141 168.759 50.9965 167.852 49.0631C166.945 47.1296 166.492 44.9207 166.492 42.4364C166.492 39.9089 166.956 37.6784 167.884 35.745C168.824 33.8007 170.13 32.2831 171.803 31.1922C173.487 30.0905 175.452 29.5396 177.698 29.5396C179.446 29.5396 181.023 29.8636 182.426 30.5117C183.829 31.1598 184.979 32.0671 185.875 33.2337C186.771 34.4002 187.327 35.7612 187.543 37.3166H183.721C183.43 36.1824 182.782 35.1779 181.778 34.303C180.785 33.4173 179.446 32.9744 177.762 32.9744C176.273 32.9744 174.966 33.3633 173.844 34.141C172.732 34.9079 171.863 35.9934 171.236 37.3976C170.621 38.791 170.313 40.4274 170.313 42.3068C170.313 44.2295 170.616 45.9037 171.22 47.3295C171.836 48.7552 172.699 49.8624 173.811 50.6509C174.934 51.4394 176.251 51.8336 177.762 51.8336C178.755 51.8336 179.657 51.6608 180.467 51.3152C181.276 50.9695 181.962 50.4727 182.523 49.8246C183.084 49.1765 183.484 48.3988 183.721 47.4915H187.543C187.327 48.9605 186.793 50.2836 185.94 51.461C185.098 52.6275 183.98 53.5564 182.588 54.2477C181.206 54.9282 179.598 55.2685 177.762 55.2685Z"/>
<path d="M203.234 55.2685C200.989 55.2685 199.019 54.7338 197.324 53.6645C195.64 52.5951 194.323 51.0991 193.373 49.1765C192.433 47.2538 191.964 45.0072 191.964 42.4364C191.964 39.8441 192.433 37.5812 193.373 35.6478C194.323 33.7143 195.64 32.2129 197.324 31.1436C199.019 30.0743 200.989 29.5396 203.234 29.5396C205.48 29.5396 207.444 30.0743 209.128 31.1436C210.823 32.2129 212.14 33.7143 213.08 35.6478C214.03 37.5812 214.505 39.8441 214.505 42.4364C214.505 45.0072 214.03 47.2538 213.08 49.1765C212.14 51.0991 210.823 52.5951 209.128 53.6645C207.444 54.7338 205.48 55.2685 203.234 55.2685ZM203.234 51.8336C204.94 51.8336 206.343 51.3962 207.444 50.5213C208.546 49.6464 209.361 48.496 209.89 47.0702C210.419 45.6444 210.683 44.0998 210.683 42.4364C210.683 40.773 210.419 39.223 209.89 37.7864C209.361 36.3499 208.546 35.1887 207.444 34.303C206.343 33.4173 204.94 32.9744 203.234 32.9744C201.528 32.9744 200.125 33.4173 199.024 34.303C197.923 35.1887 197.108 36.3499 196.579 37.7864C196.05 39.223 195.785 40.773 195.785 42.4364C195.785 44.0998 196.05 45.6444 196.579 47.0702C197.108 48.496 197.923 49.6464 199.024 50.5213C200.125 51.3962 201.528 51.8336 203.234 51.8336Z"/>
<path d="M237.956 35.4371L234.523 36.4093C234.308 35.8368 233.989 35.2805 233.568 34.7405C233.158 34.1896 232.596 33.7359 231.884 33.3795C231.171 33.023 230.259 32.8448 229.147 32.8448C227.625 32.8448 226.357 33.1959 225.342 33.8979C224.338 34.5892 223.836 35.4695 223.836 36.5389C223.836 37.4894 224.181 38.2401 224.872 38.791C225.563 39.3418 226.643 39.8009 228.111 40.1681L231.803 41.0755C234.027 41.6155 235.684 42.4418 236.774 43.5544C237.865 44.6561 238.41 46.0765 238.41 47.8155C238.41 49.2413 238 50.5159 237.179 51.6392C236.369 52.7625 235.236 53.6483 233.779 54.2963C232.321 54.9444 230.626 55.2685 228.694 55.2685C226.157 55.2685 224.057 54.7176 222.395 53.6159C220.732 52.5141 219.68 50.9047 219.237 48.7876L222.864 47.8803C223.21 49.2197 223.863 50.2242 224.824 50.8939C225.795 51.5636 227.064 51.8984 228.629 51.8984C230.41 51.8984 231.825 51.5204 232.872 50.7643C233.93 49.9974 234.459 49.0793 234.459 48.0099C234.459 47.1458 234.156 46.4221 233.552 45.8389C232.947 45.2448 232.019 44.8019 230.767 44.5103L226.621 43.5382C224.343 42.9981 222.67 42.161 221.601 41.0269C220.543 39.8819 220.014 38.4507 220.014 36.7333C220.014 35.3291 220.408 34.087 221.196 33.0068C221.995 31.9267 223.08 31.0788 224.451 30.4631C225.833 29.8474 227.398 29.5396 229.147 29.5396C231.609 29.5396 233.541 30.0797 234.944 31.1598C236.359 32.2399 237.363 33.6657 237.956 35.4371Z"/>
<path d="M254.979 29.8636V33.104H242.09V29.8636H254.979ZM245.847 23.9013H249.668V47.6211C249.668 48.7012 249.825 49.5113 250.138 50.0514C250.462 50.5807 250.872 50.9371 251.368 51.1207C251.876 51.2936 252.41 51.38 252.972 51.38C253.393 51.38 253.738 51.3584 254.008 51.3152C254.278 51.2612 254.494 51.218 254.656 51.1855L255.433 54.6204C255.174 54.7176 254.812 54.8148 254.348 54.912C253.884 55.02 253.295 55.074 252.583 55.074C251.503 55.074 250.445 54.8418 249.409 54.3774C248.383 53.9129 247.531 53.2054 246.85 52.2549C246.181 51.3044 245.847 50.1054 245.847 48.658V23.9013Z"/>
<path d="M259.497 54.75V29.8636H267.983V34.5946H268.242C268.76 33.0392 269.645 31.8079 270.897 30.9006C272.15 29.9933 273.639 29.5396 275.367 29.5396C277.116 29.5396 278.622 30.0041 279.885 30.933C281.148 31.8511 281.909 33.0716 282.168 34.5946H282.427C282.848 33.0716 283.744 31.8511 285.115 30.933C286.486 30.0041 288.095 29.5396 289.941 29.5396C292.326 29.5396 294.259 30.3065 295.738 31.8403C297.227 33.3741 297.972 35.4155 297.972 37.9647V54.75H289.034V40.233C289.034 39.142 288.758 38.2887 288.208 37.673C287.657 37.0465 286.918 36.7333 285.989 36.7333C285.072 36.7333 284.343 37.0465 283.803 37.673C283.274 38.2887 283.01 39.142 283.01 40.233V54.75H274.46V40.233C274.46 39.142 274.185 38.2887 273.634 37.673C273.083 37.0465 272.344 36.7333 271.416 36.7333C270.8 36.7333 270.271 36.8737 269.829 37.1546C269.386 37.4354 269.041 37.8404 268.792 38.3697C268.555 38.8882 268.436 39.5093 268.436 40.233V54.75H259.497Z"/>
<path d="M302.381 54.75V29.8636H311.32V54.75H302.381ZM306.85 27.2713C305.641 27.2713 304.605 26.8717 303.741 26.0724C302.878 25.2731 302.446 24.3117 302.446 23.1884C302.446 22.065 302.878 21.1037 303.741 20.3044C304.605 19.5051 305.641 19.1055 306.85 19.1055C308.07 19.1055 309.107 19.5051 309.959 20.3044C310.823 21.1037 311.255 22.065 311.255 23.1884C311.255 24.3117 310.823 25.2731 309.959 26.0724C309.107 26.8717 308.07 27.2713 306.85 27.2713Z"/>
<path d="M323.906 48.8524L323.971 38.2239H325.136L331.16 29.8636H341.2L331.096 42.8901H328.569L323.906 48.8524ZM315.874 54.75V21.5682H324.813V54.75H315.874ZM331.225 54.75L325.525 44.8991L331.355 38.5479L341.459 54.75H331.225Z"/>
<path d="M359.656 43.8622V29.8636H368.595V54.75H360.11V50.019H359.851C359.311 51.6068 358.366 52.849 357.017 53.7455C355.667 54.6312 354.064 55.074 352.207 55.074C350.469 55.074 348.947 54.6744 347.641 53.8751C346.345 53.0758 345.336 51.974 344.613 50.5699C343.9 49.1657 343.539 47.5563 343.528 45.7417V29.8636H352.466V43.8622C352.477 45.0936 352.79 46.0603 353.406 46.7624C354.032 47.4645 354.906 47.8155 356.029 47.8155C356.774 47.8155 357.416 47.6589 357.956 47.3457C358.507 47.0216 358.928 46.568 359.219 45.9847C359.521 45.3906 359.667 44.6831 359.656 43.8622Z"/>
<path d="M206.392 79.9993L199.526 81.9435C199.094 80.7986 198.457 79.686 197.615 78.6059C196.795 77.5042 195.672 76.5969 194.247 75.884C192.822 75.1711 190.998 74.8146 188.774 74.8146C185.729 74.8146 183.192 75.5167 181.163 76.9209C179.155 78.3035 178.151 80.0641 178.151 82.2028C178.151 84.1038 178.842 85.6052 180.224 86.7069C181.605 87.8087 183.765 88.7268 186.701 89.4613L194.085 91.2759C198.533 92.3561 201.847 94.0087 204.028 96.2338C206.208 98.4372 207.299 101.278 207.299 104.756C207.299 107.608 206.478 110.157 204.837 112.403C203.218 114.65 200.951 116.422 198.036 117.718C195.121 119.014 191.732 119.662 187.867 119.662C182.793 119.662 178.594 118.56 175.269 116.357C171.944 114.153 169.838 110.934 168.953 106.7L176.208 104.886C176.899 107.564 178.205 109.573 180.126 110.913C182.07 112.252 184.607 112.922 187.737 112.922C191.3 112.922 194.128 112.166 196.223 110.654C198.338 109.12 199.396 107.284 199.396 105.145C199.396 103.417 198.792 101.969 197.583 100.803C196.374 99.6146 194.517 98.7289 192.012 98.1456L183.721 96.2014C179.166 95.1212 175.819 93.447 173.682 91.1787C171.566 88.8888 170.508 86.0265 170.508 82.5916C170.508 79.7833 171.296 77.2989 172.872 75.1387C174.47 72.9784 176.64 71.2826 179.382 70.0512C182.145 68.8199 185.276 68.2042 188.774 68.2042C193.696 68.2042 197.561 69.2843 200.368 71.4446C203.196 73.6049 205.204 76.4564 206.392 79.9993Z"/>
<path d="M239.661 119.662C234.868 119.662 230.733 118.603 227.257 116.486C223.802 114.348 221.136 111.366 219.257 107.543C217.4 103.697 216.472 99.2257 216.472 94.1275C216.472 89.0292 217.4 84.5359 219.257 80.6474C221.136 76.7373 223.748 73.6913 227.095 71.5094C230.463 69.3059 234.393 68.2042 238.883 68.2042C241.474 68.2042 244.033 68.6362 246.559 69.5004C249.085 70.3645 251.385 71.7686 253.457 73.7129C255.53 75.6355 257.182 78.1847 258.412 81.3603C259.643 84.5359 260.258 88.446 260.258 93.0905V96.331H221.913V89.7205H252.486C252.486 86.9122 251.924 84.4062 250.802 82.2028C249.7 79.9993 248.124 78.2603 246.073 76.9857C244.044 75.7111 241.647 75.0739 238.883 75.0739C235.839 75.0739 233.205 75.83 230.981 77.3421C228.779 78.8327 227.084 80.777 225.897 83.1749C224.709 85.5728 224.115 88.1435 224.115 90.8871V95.294C224.115 99.0529 224.763 102.239 226.058 104.853C227.375 107.446 229.2 109.422 231.532 110.783C233.864 112.123 236.573 112.792 239.661 112.792C241.669 112.792 243.482 112.511 245.102 111.95C246.743 111.366 248.157 110.502 249.344 109.357C250.532 108.191 251.449 106.743 252.097 105.015L259.481 107.089C258.704 109.595 257.398 111.799 255.562 113.7C253.727 115.579 251.46 117.048 248.761 118.107C246.062 119.143 243.029 119.662 239.661 119.662Z"/>
<path d="M286.524 119.792C283.372 119.792 280.511 119.197 277.941 118.009C275.372 116.8 273.332 115.061 271.82 112.792C270.309 110.502 269.553 107.737 269.553 104.497C269.553 101.645 270.115 99.3337 271.237 97.5623C272.36 95.7693 273.861 94.3651 275.739 93.3498C277.618 92.3345 279.69 91.5784 281.957 91.0815C284.246 90.563 286.545 90.1526 288.856 89.8501C291.878 89.4613 294.329 89.1697 296.207 88.9752C298.107 88.7592 299.489 88.4028 300.353 87.9059C301.238 87.409 301.681 86.5449 301.681 85.3136V85.0543C301.681 81.8571 300.806 79.3728 299.057 77.6014C297.33 75.83 294.707 74.9442 291.187 74.9442C287.539 74.9442 284.678 75.7435 282.605 77.3421C280.532 78.9408 279.075 80.6474 278.233 82.462L270.978 79.8697C272.274 76.8453 274.001 74.4906 276.16 72.8056C278.341 71.099 280.716 69.9108 283.285 69.2411C285.876 68.5498 288.424 68.2042 290.928 68.2042C292.526 68.2042 294.361 68.3986 296.434 68.7875C298.528 69.1547 300.547 69.9216 302.49 71.0882C304.455 72.2547 306.085 74.0153 307.381 76.37C308.676 78.7247 309.324 81.8787 309.324 85.832V118.625H301.681V111.885H301.292C300.774 112.965 299.91 114.121 298.701 115.352C297.492 116.584 295.883 117.631 293.875 118.495C291.868 119.359 289.417 119.792 286.524 119.792ZM287.69 112.922C290.712 112.922 293.26 112.328 295.333 111.14C297.427 109.951 299.003 108.418 300.061 106.538C301.141 104.659 301.681 102.682 301.681 100.608V93.609C301.357 93.9979 300.644 94.3543 299.543 94.6783C298.464 94.9808 297.211 95.2508 295.786 95.4885C294.383 95.7045 293.012 95.8989 291.673 96.0717C290.356 96.223 289.287 96.3526 288.467 96.4606C286.481 96.7198 284.624 97.1411 282.897 97.7243C281.191 98.286 279.809 99.1393 278.751 100.284C277.715 101.408 277.197 102.941 277.197 104.886C277.197 107.543 278.179 109.552 280.144 110.913C282.13 112.252 284.645 112.922 287.69 112.922Z"/>
<path d="M323.274 118.625V68.8523H330.658V76.37H331.176C332.083 73.9073 333.724 71.9091 336.099 70.3753C338.474 68.8415 341.151 68.0746 344.131 68.0746C344.692 68.0746 345.394 68.0854 346.236 68.107C347.078 68.1286 347.715 68.161 348.147 68.2042V75.9812C347.888 75.9164 347.294 75.8192 346.366 75.6895C345.459 75.5383 344.498 75.4627 343.483 75.4627C341.065 75.4627 338.906 75.9704 337.006 76.9857C335.128 77.9794 333.638 79.362 332.537 81.1334C331.457 82.8833 330.917 84.8815 330.917 87.1282V118.625H323.274Z"/>
<path d="M375.902 119.662C371.238 119.662 367.223 118.56 363.854 116.357C360.486 114.153 357.895 111.118 356.082 107.251C354.268 103.384 353.361 98.9665 353.361 93.9979C353.361 88.9428 354.29 84.4819 356.146 80.615C358.025 76.7265 360.637 73.6913 363.984 71.5094C367.352 69.3059 371.282 68.2042 375.772 68.2042C379.27 68.2042 382.422 68.8523 385.229 70.1484C388.036 71.4446 390.336 73.2592 392.128 75.5923C393.92 77.9254 395.032 80.6474 395.463 83.7582H387.82C387.237 81.4899 385.942 79.4808 383.934 77.731C381.947 75.9596 379.27 75.0739 375.902 75.0739C372.922 75.0739 370.31 75.8516 368.065 77.407C365.841 78.9408 364.103 81.1118 362.85 83.9202C361.62 86.7069 361.004 89.9798 361.004 93.7386C361.004 97.5839 361.609 100.932 362.818 103.784C364.049 106.635 365.776 108.85 368 110.427C370.245 112.004 372.879 112.792 375.902 112.792C377.888 112.792 379.691 112.447 381.311 111.755C382.93 111.064 384.301 110.07 385.424 108.774C386.546 107.478 387.345 105.923 387.82 104.108H395.463C395.032 107.046 393.963 109.692 392.257 112.047C390.573 114.38 388.338 116.238 385.553 117.62C382.79 118.981 379.572 119.662 375.902 119.662Z"/>
<path d="M414.28 88.6836V118.625H406.637V52.2614H414.28V76.6293H414.928C416.094 74.0585 417.842 72.0171 420.174 70.5049C422.528 68.9711 425.658 68.2042 429.566 68.2042C432.956 68.2042 435.925 68.8847 438.472 70.2456C441.02 71.585 442.996 73.6481 444.399 76.4348C445.824 79.2 446.537 82.7212 446.537 86.9986V118.625H438.894V87.517C438.894 83.5637 437.868 80.507 435.817 78.3467C433.787 76.1648 430.97 75.0739 427.364 75.0739C424.859 75.0739 422.614 75.6031 420.628 76.6617C418.663 77.7202 417.108 79.2648 415.964 81.2955C414.841 83.3261 414.28 85.7888 414.28 88.6836Z"/>
</mask>
<path d="M177.762 55.2685C175.43 55.2685 173.423 54.7176 171.738 53.6159C170.054 52.5141 168.759 50.9965 167.852 49.0631C166.945 47.1296 166.492 44.9207 166.492 42.4364C166.492 39.9089 166.956 37.6784 167.884 35.745C168.824 33.8007 170.13 32.2831 171.803 31.1922C173.487 30.0905 175.452 29.5396 177.698 29.5396C179.446 29.5396 181.023 29.8636 182.426 30.5117C183.829 31.1598 184.979 32.0671 185.875 33.2337C186.771 34.4002 187.327 35.7612 187.543 37.3166H183.721C183.43 36.1824 182.782 35.1779 181.778 34.303C180.785 33.4173 179.446 32.9744 177.762 32.9744C176.273 32.9744 174.966 33.3633 173.844 34.141C172.732 34.9079 171.863 35.9934 171.236 37.3976C170.621 38.791 170.313 40.4274 170.313 42.3068C170.313 44.2295 170.616 45.9037 171.22 47.3295C171.836 48.7552 172.699 49.8624 173.811 50.6509C174.934 51.4394 176.251 51.8336 177.762 51.8336C178.755 51.8336 179.657 51.6608 180.467 51.3152C181.276 50.9695 181.962 50.4727 182.523 49.8246C183.084 49.1765 183.484 48.3988 183.721 47.4915H187.543C187.327 48.9605 186.793 50.2836 185.94 51.461C185.098 52.6275 183.98 53.5564 182.588 54.2477C181.206 54.9282 179.598 55.2685 177.762 55.2685Z" fill="white"/>
<path d="M203.234 55.2685C200.989 55.2685 199.019 54.7338 197.324 53.6645C195.64 52.5951 194.323 51.0991 193.373 49.1765C192.433 47.2538 191.964 45.0072 191.964 42.4364C191.964 39.8441 192.433 37.5812 193.373 35.6478C194.323 33.7143 195.64 32.2129 197.324 31.1436C199.019 30.0743 200.989 29.5396 203.234 29.5396C205.48 29.5396 207.444 30.0743 209.128 31.1436C210.823 32.2129 212.14 33.7143 213.08 35.6478C214.03 37.5812 214.505 39.8441 214.505 42.4364C214.505 45.0072 214.03 47.2538 213.08 49.1765C212.14 51.0991 210.823 52.5951 209.128 53.6645C207.444 54.7338 205.48 55.2685 203.234 55.2685ZM203.234 51.8336C204.94 51.8336 206.343 51.3962 207.444 50.5213C208.546 49.6464 209.361 48.496 209.89 47.0702C210.419 45.6444 210.683 44.0998 210.683 42.4364C210.683 40.773 210.419 39.223 209.89 37.7864C209.361 36.3499 208.546 35.1887 207.444 34.303C206.343 33.4173 204.94 32.9744 203.234 32.9744C201.528 32.9744 200.125 33.4173 199.024 34.303C197.923 35.1887 197.108 36.3499 196.579 37.7864C196.05 39.223 195.785 40.773 195.785 42.4364C195.785 44.0998 196.05 45.6444 196.579 47.0702C197.108 48.496 197.923 49.6464 199.024 50.5213C200.125 51.3962 201.528 51.8336 203.234 51.8336Z" fill="white"/>
<path d="M237.956 35.4371L234.523 36.4093C234.308 35.8368 233.989 35.2805 233.568 34.7405C233.158 34.1896 232.596 33.7359 231.884 33.3795C231.171 33.023 230.259 32.8448 229.147 32.8448C227.625 32.8448 226.357 33.1959 225.342 33.8979C224.338 34.5892 223.836 35.4695 223.836 36.5389C223.836 37.4894 224.181 38.2401 224.872 38.791C225.563 39.3418 226.643 39.8009 228.111 40.1681L231.803 41.0755C234.027 41.6155 235.684 42.4418 236.774 43.5544C237.865 44.6561 238.41 46.0765 238.41 47.8155C238.41 49.2413 238 50.5159 237.179 51.6392C236.369 52.7625 235.236 53.6483 233.779 54.2963C232.321 54.9444 230.626 55.2685 228.694 55.2685C226.157 55.2685 224.057 54.7176 222.395 53.6159C220.732 52.5141 219.68 50.9047 219.237 48.7876L222.864 47.8803C223.21 49.2197 223.863 50.2242 224.824 50.8939C225.795 51.5636 227.064 51.8984 228.629 51.8984C230.41 51.8984 231.825 51.5204 232.872 50.7643C233.93 49.9974 234.459 49.0793 234.459 48.0099C234.459 47.1458 234.156 46.4221 233.552 45.8389C232.947 45.2448 232.019 44.8019 230.767 44.5103L226.621 43.5382C224.343 42.9981 222.67 42.161 221.601 41.0269C220.543 39.8819 220.014 38.4507 220.014 36.7333C220.014 35.3291 220.408 34.087 221.196 33.0068C221.995 31.9267 223.08 31.0788 224.451 30.4631C225.833 29.8474 227.398 29.5396 229.147 29.5396C231.609 29.5396 233.541 30.0797 234.944 31.1598C236.359 32.2399 237.363 33.6657 237.956 35.4371Z" fill="white"/>
<path d="M254.979 29.8636V33.104H242.09V29.8636H254.979ZM245.847 23.9013H249.668V47.6211C249.668 48.7012 249.825 49.5113 250.138 50.0514C250.462 50.5807 250.872 50.9371 251.368 51.1207C251.876 51.2936 252.41 51.38 252.972 51.38C253.393 51.38 253.738 51.3584 254.008 51.3152C254.278 51.2612 254.494 51.218 254.656 51.1855L255.433 54.6204C255.174 54.7176 254.812 54.8148 254.348 54.912C253.884 55.02 253.295 55.074 252.583 55.074C251.503 55.074 250.445 54.8418 249.409 54.3774C248.383 53.9129 247.531 53.2054 246.85 52.2549C246.181 51.3044 245.847 50.1054 245.847 48.658V23.9013Z" fill="white"/>
<path d="M259.497 54.75V29.8636H267.983V34.5946H268.242C268.76 33.0392 269.645 31.8079 270.897 30.9006C272.15 29.9933 273.639 29.5396 275.367 29.5396C277.116 29.5396 278.622 30.0041 279.885 30.933C281.148 31.8511 281.909 33.0716 282.168 34.5946H282.427C282.848 33.0716 283.744 31.8511 285.115 30.933C286.486 30.0041 288.095 29.5396 289.941 29.5396C292.326 29.5396 294.259 30.3065 295.738 31.8403C297.227 33.3741 297.972 35.4155 297.972 37.9647V54.75H289.034V40.233C289.034 39.142 288.758 38.2887 288.208 37.673C287.657 37.0465 286.918 36.7333 285.989 36.7333C285.072 36.7333 284.343 37.0465 283.803 37.673C283.274 38.2887 283.01 39.142 283.01 40.233V54.75H274.46V40.233C274.46 39.142 274.185 38.2887 273.634 37.673C273.083 37.0465 272.344 36.7333 271.416 36.7333C270.8 36.7333 270.271 36.8737 269.829 37.1546C269.386 37.4354 269.041 37.8404 268.792 38.3697C268.555 38.8882 268.436 39.5093 268.436 40.233V54.75H259.497Z" fill="white"/>
<path d="M302.381 54.75V29.8636H311.32V54.75H302.381ZM306.85 27.2713C305.641 27.2713 304.605 26.8717 303.741 26.0724C302.878 25.2731 302.446 24.3117 302.446 23.1884C302.446 22.065 302.878 21.1037 303.741 20.3044C304.605 19.5051 305.641 19.1055 306.85 19.1055C308.07 19.1055 309.107 19.5051 309.959 20.3044C310.823 21.1037 311.255 22.065 311.255 23.1884C311.255 24.3117 310.823 25.2731 309.959 26.0724C309.107 26.8717 308.07 27.2713 306.85 27.2713Z" fill="white"/>
<path d="M323.906 48.8524L323.971 38.2239H325.136L331.16 29.8636H341.2L331.096 42.8901H328.569L323.906 48.8524ZM315.874 54.75V21.5682H324.813V54.75H315.874ZM331.225 54.75L325.525 44.8991L331.355 38.5479L341.459 54.75H331.225Z" fill="white"/>
<path d="M359.656 43.8622V29.8636H368.595V54.75H360.11V50.019H359.851C359.311 51.6068 358.366 52.849 357.017 53.7455C355.667 54.6312 354.064 55.074 352.207 55.074C350.469 55.074 348.947 54.6744 347.641 53.8751C346.345 53.0758 345.336 51.974 344.613 50.5699C343.9 49.1657 343.539 47.5563 343.528 45.7417V29.8636H352.466V43.8622C352.477 45.0936 352.79 46.0603 353.406 46.7624C354.032 47.4645 354.906 47.8155 356.029 47.8155C356.774 47.8155 357.416 47.6589 357.956 47.3457C358.507 47.0216 358.928 46.568 359.219 45.9847C359.521 45.3906 359.667 44.6831 359.656 43.8622Z" fill="white"/>
<path d="M206.392 79.9993L199.526 81.9435C199.094 80.7986 198.457 79.686 197.615 78.6059C196.795 77.5042 195.672 76.5969 194.247 75.884C192.822 75.1711 190.998 74.8146 188.774 74.8146C185.729 74.8146 183.192 75.5167 181.163 76.9209C179.155 78.3035 178.151 80.0641 178.151 82.2028C178.151 84.1038 178.842 85.6052 180.224 86.7069C181.605 87.8087 183.765 88.7268 186.701 89.4613L194.085 91.2759C198.533 92.3561 201.847 94.0087 204.028 96.2338C206.208 98.4372 207.299 101.278 207.299 104.756C207.299 107.608 206.478 110.157 204.837 112.403C203.218 114.65 200.951 116.422 198.036 117.718C195.121 119.014 191.732 119.662 187.867 119.662C182.793 119.662 178.594 118.56 175.269 116.357C171.944 114.153 169.838 110.934 168.953 106.7L176.208 104.886C176.899 107.564 178.205 109.573 180.126 110.913C182.07 112.252 184.607 112.922 187.737 112.922C191.3 112.922 194.128 112.166 196.223 110.654C198.338 109.12 199.396 107.284 199.396 105.145C199.396 103.417 198.792 101.969 197.583 100.803C196.374 99.6146 194.517 98.7289 192.012 98.1456L183.721 96.2014C179.166 95.1212 175.819 93.447 173.682 91.1787C171.566 88.8888 170.508 86.0265 170.508 82.5916C170.508 79.7833 171.296 77.2989 172.872 75.1387C174.47 72.9784 176.64 71.2826 179.382 70.0512C182.145 68.8199 185.276 68.2042 188.774 68.2042C193.696 68.2042 197.561 69.2843 200.368 71.4446C203.196 73.6049 205.204 76.4564 206.392 79.9993Z" fill="white"/>
<path d="M239.661 119.662C234.868 119.662 230.733 118.603 227.257 116.486C223.802 114.348 221.136 111.366 219.257 107.543C217.4 103.697 216.472 99.2257 216.472 94.1275C216.472 89.0292 217.4 84.5359 219.257 80.6474C221.136 76.7373 223.748 73.6913 227.095 71.5094C230.463 69.3059 234.393 68.2042 238.883 68.2042C241.474 68.2042 244.033 68.6362 246.559 69.5004C249.085 70.3645 251.385 71.7686 253.457 73.7129C255.53 75.6355 257.182 78.1847 258.412 81.3603C259.643 84.5359 260.258 88.446 260.258 93.0905V96.331H221.913V89.7205H252.486C252.486 86.9122 251.924 84.4062 250.802 82.2028C249.7 79.9993 248.124 78.2603 246.073 76.9857C244.044 75.7111 241.647 75.0739 238.883 75.0739C235.839 75.0739 233.205 75.83 230.981 77.3421C228.779 78.8327 227.084 80.777 225.897 83.1749C224.709 85.5728 224.115 88.1435 224.115 90.8871V95.294C224.115 99.0529 224.763 102.239 226.058 104.853C227.375 107.446 229.2 109.422 231.532 110.783C233.864 112.123 236.573 112.792 239.661 112.792C241.669 112.792 243.482 112.511 245.102 111.95C246.743 111.366 248.157 110.502 249.344 109.357C250.532 108.191 251.449 106.743 252.097 105.015L259.481 107.089C258.704 109.595 257.398 111.799 255.562 113.7C253.727 115.579 251.46 117.048 248.761 118.107C246.062 119.143 243.029 119.662 239.661 119.662Z" fill="white"/>
<path d="M286.524 119.792C283.372 119.792 280.511 119.197 277.941 118.009C275.372 116.8 273.332 115.061 271.82 112.792C270.309 110.502 269.553 107.737 269.553 104.497C269.553 101.645 270.115 99.3337 271.237 97.5623C272.36 95.7693 273.861 94.3651 275.739 93.3498C277.618 92.3345 279.69 91.5784 281.957 91.0815C284.246 90.563 286.545 90.1526 288.856 89.8501C291.878 89.4613 294.329 89.1697 296.207 88.9752C298.107 88.7592 299.489 88.4028 300.353 87.9059C301.238 87.409 301.681 86.5449 301.681 85.3136V85.0543C301.681 81.8571 300.806 79.3728 299.057 77.6014C297.33 75.83 294.707 74.9442 291.187 74.9442C287.539 74.9442 284.678 75.7435 282.605 77.3421C280.532 78.9408 279.075 80.6474 278.233 82.462L270.978 79.8697C272.274 76.8453 274.001 74.4906 276.16 72.8056C278.341 71.099 280.716 69.9108 283.285 69.2411C285.876 68.5498 288.424 68.2042 290.928 68.2042C292.526 68.2042 294.361 68.3986 296.434 68.7875C298.528 69.1547 300.547 69.9216 302.49 71.0882C304.455 72.2547 306.085 74.0153 307.381 76.37C308.676 78.7247 309.324 81.8787 309.324 85.832V118.625H301.681V111.885H301.292C300.774 112.965 299.91 114.121 298.701 115.352C297.492 116.584 295.883 117.631 293.875 118.495C291.868 119.359 289.417 119.792 286.524 119.792ZM287.69 112.922C290.712 112.922 293.26 112.328 295.333 111.14C297.427 109.951 299.003 108.418 300.061 106.538C301.141 104.659 301.681 102.682 301.681 100.608V93.609C301.357 93.9979 300.644 94.3543 299.543 94.6783C298.464 94.9808 297.211 95.2508 295.786 95.4885C294.383 95.7045 293.012 95.8989 291.673 96.0717C290.356 96.223 289.287 96.3526 288.467 96.4606C286.481 96.7198 284.624 97.1411 282.897 97.7243C281.191 98.286 279.809 99.1393 278.751 100.284C277.715 101.408 277.197 102.941 277.197 104.886C277.197 107.543 278.179 109.552 280.144 110.913C282.13 112.252 284.645 112.922 287.69 112.922Z" fill="white"/>
<path d="M323.274 118.625V68.8523H330.658V76.37H331.176C332.083 73.9073 333.724 71.9091 336.099 70.3753C338.474 68.8415 341.151 68.0746 344.131 68.0746C344.692 68.0746 345.394 68.0854 346.236 68.107C347.078 68.1286 347.715 68.161 348.147 68.2042V75.9812C347.888 75.9164 347.294 75.8192 346.366 75.6895C345.459 75.5383 344.498 75.4627 343.483 75.4627C341.065 75.4627 338.906 75.9704 337.006 76.9857C335.128 77.9794 333.638 79.362 332.537 81.1334C331.457 82.8833 330.917 84.8815 330.917 87.1282V118.625H323.274Z" fill="white"/>
<path d="M375.902 119.662C371.238 119.662 367.223 118.56 363.854 116.357C360.486 114.153 357.895 111.118 356.082 107.251C354.268 103.384 353.361 98.9665 353.361 93.9979C353.361 88.9428 354.29 84.4819 356.146 80.615C358.025 76.7265 360.637 73.6913 363.984 71.5094C367.352 69.3059 371.282 68.2042 375.772 68.2042C379.27 68.2042 382.422 68.8523 385.229 70.1484C388.036 71.4446 390.336 73.2592 392.128 75.5923C393.92 77.9254 395.032 80.6474 395.463 83.7582H387.82C387.237 81.4899 385.942 79.4808 383.934 77.731C381.947 75.9596 379.27 75.0739 375.902 75.0739C372.922 75.0739 370.31 75.8516 368.065 77.407C365.841 78.9408 364.103 81.1118 362.85 83.9202C361.62 86.7069 361.004 89.9798 361.004 93.7386C361.004 97.5839 361.609 100.932 362.818 103.784C364.049 106.635 365.776 108.85 368 110.427C370.245 112.004 372.879 112.792 375.902 112.792C377.888 112.792 379.691 112.447 381.311 111.755C382.93 111.064 384.301 110.07 385.424 108.774C386.546 107.478 387.345 105.923 387.82 104.108H395.463C395.032 107.046 393.963 109.692 392.257 112.047C390.573 114.38 388.338 116.238 385.553 117.62C382.79 118.981 379.572 119.662 375.902 119.662Z" fill="white"/>
<path d="M414.28 88.6836V118.625H406.637V52.2614H414.28V76.6293H414.928C416.094 74.0585 417.842 72.0171 420.174 70.5049C422.528 68.9711 425.658 68.2042 429.566 68.2042C432.956 68.2042 435.925 68.8847 438.472 70.2456C441.02 71.585 442.996 73.6481 444.399 76.4348C445.824 79.2 446.537 82.7212 446.537 86.9986V118.625H438.894V87.517C438.894 83.5637 437.868 80.507 435.817 78.3467C433.787 76.1648 430.97 75.0739 427.364 75.0739C424.859 75.0739 422.614 75.6031 420.628 76.6617C418.663 77.7202 417.108 79.2648 415.964 81.2955C414.841 83.3261 414.28 85.7888 414.28 88.6836Z" fill="white"/>
<path d="M177.762 55.2685C175.43 55.2685 173.423 54.7176 171.738 53.6159C170.054 52.5141 168.759 50.9965 167.852 49.0631C166.945 47.1296 166.492 44.9207 166.492 42.4364C166.492 39.9089 166.956 37.6784 167.884 35.745C168.824 33.8007 170.13 32.2831 171.803 31.1922C173.487 30.0905 175.452 29.5396 177.698 29.5396C179.446 29.5396 181.023 29.8636 182.426 30.5117C183.829 31.1598 184.979 32.0671 185.875 33.2337C186.771 34.4002 187.327 35.7612 187.543 37.3166H183.721C183.43 36.1824 182.782 35.1779 181.778 34.303C180.785 33.4173 179.446 32.9744 177.762 32.9744C176.273 32.9744 174.966 33.3633 173.844 34.141C172.732 34.9079 171.863 35.9934 171.236 37.3976C170.621 38.791 170.313 40.4274 170.313 42.3068C170.313 44.2295 170.616 45.9037 171.22 47.3295C171.836 48.7552 172.699 49.8624 173.811 50.6509C174.934 51.4394 176.251 51.8336 177.762 51.8336C178.755 51.8336 179.657 51.6608 180.467 51.3152C181.276 50.9695 181.962 50.4727 182.523 49.8246C183.084 49.1765 183.484 48.3988 183.721 47.4915H187.543C187.327 48.9605 186.793 50.2836 185.94 51.461C185.098 52.6275 183.98 53.5564 182.588 54.2477C181.206 54.9282 179.598 55.2685 177.762 55.2685Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M203.234 55.2685C200.989 55.2685 199.019 54.7338 197.324 53.6645C195.64 52.5951 194.323 51.0991 193.373 49.1765C192.433 47.2538 191.964 45.0072 191.964 42.4364C191.964 39.8441 192.433 37.5812 193.373 35.6478C194.323 33.7143 195.64 32.2129 197.324 31.1436C199.019 30.0743 200.989 29.5396 203.234 29.5396C205.48 29.5396 207.444 30.0743 209.128 31.1436C210.823 32.2129 212.14 33.7143 213.08 35.6478C214.03 37.5812 214.505 39.8441 214.505 42.4364C214.505 45.0072 214.03 47.2538 213.08 49.1765C212.14 51.0991 210.823 52.5951 209.128 53.6645C207.444 54.7338 205.48 55.2685 203.234 55.2685ZM203.234 51.8336C204.94 51.8336 206.343 51.3962 207.444 50.5213C208.546 49.6464 209.361 48.496 209.89 47.0702C210.419 45.6444 210.683 44.0998 210.683 42.4364C210.683 40.773 210.419 39.223 209.89 37.7864C209.361 36.3499 208.546 35.1887 207.444 34.303C206.343 33.4173 204.94 32.9744 203.234 32.9744C201.528 32.9744 200.125 33.4173 199.024 34.303C197.923 35.1887 197.108 36.3499 196.579 37.7864C196.05 39.223 195.785 40.773 195.785 42.4364C195.785 44.0998 196.05 45.6444 196.579 47.0702C197.108 48.496 197.923 49.6464 199.024 50.5213C200.125 51.3962 201.528 51.8336 203.234 51.8336Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M237.956 35.4371L234.523 36.4093C234.308 35.8368 233.989 35.2805 233.568 34.7405C233.158 34.1896 232.596 33.7359 231.884 33.3795C231.171 33.023 230.259 32.8448 229.147 32.8448C227.625 32.8448 226.357 33.1959 225.342 33.8979C224.338 34.5892 223.836 35.4695 223.836 36.5389C223.836 37.4894 224.181 38.2401 224.872 38.791C225.563 39.3418 226.643 39.8009 228.111 40.1681L231.803 41.0755C234.027 41.6155 235.684 42.4418 236.774 43.5544C237.865 44.6561 238.41 46.0765 238.41 47.8155C238.41 49.2413 238 50.5159 237.179 51.6392C236.369 52.7625 235.236 53.6483 233.779 54.2963C232.321 54.9444 230.626 55.2685 228.694 55.2685C226.157 55.2685 224.057 54.7176 222.395 53.6159C220.732 52.5141 219.68 50.9047 219.237 48.7876L222.864 47.8803C223.21 49.2197 223.863 50.2242 224.824 50.8939C225.795 51.5636 227.064 51.8984 228.629 51.8984C230.41 51.8984 231.825 51.5204 232.872 50.7643C233.93 49.9974 234.459 49.0793 234.459 48.0099C234.459 47.1458 234.156 46.4221 233.552 45.8389C232.947 45.2448 232.019 44.8019 230.767 44.5103L226.621 43.5382C224.343 42.9981 222.67 42.161 221.601 41.0269C220.543 39.8819 220.014 38.4507 220.014 36.7333C220.014 35.3291 220.408 34.087 221.196 33.0068C221.995 31.9267 223.08 31.0788 224.451 30.4631C225.833 29.8474 227.398 29.5396 229.147 29.5396C231.609 29.5396 233.541 30.0797 234.944 31.1598C236.359 32.2399 237.363 33.6657 237.956 35.4371Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M254.979 29.8636V33.104H242.09V29.8636H254.979ZM245.847 23.9013H249.668V47.6211C249.668 48.7012 249.825 49.5113 250.138 50.0514C250.462 50.5807 250.872 50.9371 251.368 51.1207C251.876 51.2936 252.41 51.38 252.972 51.38C253.393 51.38 253.738 51.3584 254.008 51.3152C254.278 51.2612 254.494 51.218 254.656 51.1855L255.433 54.6204C255.174 54.7176 254.812 54.8148 254.348 54.912C253.884 55.02 253.295 55.074 252.583 55.074C251.503 55.074 250.445 54.8418 249.409 54.3774C248.383 53.9129 247.531 53.2054 246.85 52.2549C246.181 51.3044 245.847 50.1054 245.847 48.658V23.9013Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M259.497 54.75V29.8636H267.983V34.5946H268.242C268.76 33.0392 269.645 31.8079 270.897 30.9006C272.15 29.9933 273.639 29.5396 275.367 29.5396C277.116 29.5396 278.622 30.0041 279.885 30.933C281.148 31.8511 281.909 33.0716 282.168 34.5946H282.427C282.848 33.0716 283.744 31.8511 285.115 30.933C286.486 30.0041 288.095 29.5396 289.941 29.5396C292.326 29.5396 294.259 30.3065 295.738 31.8403C297.227 33.3741 297.972 35.4155 297.972 37.9647V54.75H289.034V40.233C289.034 39.142 288.758 38.2887 288.208 37.673C287.657 37.0465 286.918 36.7333 285.989 36.7333C285.072 36.7333 284.343 37.0465 283.803 37.673C283.274 38.2887 283.01 39.142 283.01 40.233V54.75H274.46V40.233C274.46 39.142 274.185 38.2887 273.634 37.673C273.083 37.0465 272.344 36.7333 271.416 36.7333C270.8 36.7333 270.271 36.8737 269.829 37.1546C269.386 37.4354 269.041 37.8404 268.792 38.3697C268.555 38.8882 268.436 39.5093 268.436 40.233V54.75H259.497Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M302.381 54.75V29.8636H311.32V54.75H302.381ZM306.85 27.2713C305.641 27.2713 304.605 26.8717 303.741 26.0724C302.878 25.2731 302.446 24.3117 302.446 23.1884C302.446 22.065 302.878 21.1037 303.741 20.3044C304.605 19.5051 305.641 19.1055 306.85 19.1055C308.07 19.1055 309.107 19.5051 309.959 20.3044C310.823 21.1037 311.255 22.065 311.255 23.1884C311.255 24.3117 310.823 25.2731 309.959 26.0724C309.107 26.8717 308.07 27.2713 306.85 27.2713Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M323.906 48.8524L323.971 38.2239H325.136L331.16 29.8636H341.2L331.096 42.8901H328.569L323.906 48.8524ZM315.874 54.75V21.5682H324.813V54.75H315.874ZM331.225 54.75L325.525 44.8991L331.355 38.5479L341.459 54.75H331.225Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M359.656 43.8622V29.8636H368.595V54.75H360.11V50.019H359.851C359.311 51.6068 358.366 52.849 357.017 53.7455C355.667 54.6312 354.064 55.074 352.207 55.074C350.469 55.074 348.947 54.6744 347.641 53.8751C346.345 53.0758 345.336 51.974 344.613 50.5699C343.9 49.1657 343.539 47.5563 343.528 45.7417V29.8636H352.466V43.8622C352.477 45.0936 352.79 46.0603 353.406 46.7624C354.032 47.4645 354.906 47.8155 356.029 47.8155C356.774 47.8155 357.416 47.6589 357.956 47.3457C358.507 47.0216 358.928 46.568 359.219 45.9847C359.521 45.3906 359.667 44.6831 359.656 43.8622Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M206.392 79.9993L199.526 81.9435C199.094 80.7986 198.457 79.686 197.615 78.6059C196.795 77.5042 195.672 76.5969 194.247 75.884C192.822 75.1711 190.998 74.8146 188.774 74.8146C185.729 74.8146 183.192 75.5167 181.163 76.9209C179.155 78.3035 178.151 80.0641 178.151 82.2028C178.151 84.1038 178.842 85.6052 180.224 86.7069C181.605 87.8087 183.765 88.7268 186.701 89.4613L194.085 91.2759C198.533 92.3561 201.847 94.0087 204.028 96.2338C206.208 98.4372 207.299 101.278 207.299 104.756C207.299 107.608 206.478 110.157 204.837 112.403C203.218 114.65 200.951 116.422 198.036 117.718C195.121 119.014 191.732 119.662 187.867 119.662C182.793 119.662 178.594 118.56 175.269 116.357C171.944 114.153 169.838 110.934 168.953 106.7L176.208 104.886C176.899 107.564 178.205 109.573 180.126 110.913C182.07 112.252 184.607 112.922 187.737 112.922C191.3 112.922 194.128 112.166 196.223 110.654C198.338 109.12 199.396 107.284 199.396 105.145C199.396 103.417 198.792 101.969 197.583 100.803C196.374 99.6146 194.517 98.7289 192.012 98.1456L183.721 96.2014C179.166 95.1212 175.819 93.447 173.682 91.1787C171.566 88.8888 170.508 86.0265 170.508 82.5916C170.508 79.7833 171.296 77.2989 172.872 75.1387C174.47 72.9784 176.64 71.2826 179.382 70.0512C182.145 68.8199 185.276 68.2042 188.774 68.2042C193.696 68.2042 197.561 69.2843 200.368 71.4446C203.196 73.6049 205.204 76.4564 206.392 79.9993Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M239.661 119.662C234.868 119.662 230.733 118.603 227.257 116.486C223.802 114.348 221.136 111.366 219.257 107.543C217.4 103.697 216.472 99.2257 216.472 94.1275C216.472 89.0292 217.4 84.5359 219.257 80.6474C221.136 76.7373 223.748 73.6913 227.095 71.5094C230.463 69.3059 234.393 68.2042 238.883 68.2042C241.474 68.2042 244.033 68.6362 246.559 69.5004C249.085 70.3645 251.385 71.7686 253.457 73.7129C255.53 75.6355 257.182 78.1847 258.412 81.3603C259.643 84.5359 260.258 88.446 260.258 93.0905V96.331H221.913V89.7205H252.486C252.486 86.9122 251.924 84.4062 250.802 82.2028C249.7 79.9993 248.124 78.2603 246.073 76.9857C244.044 75.7111 241.647 75.0739 238.883 75.0739C235.839 75.0739 233.205 75.83 230.981 77.3421C228.779 78.8327 227.084 80.777 225.897 83.1749C224.709 85.5728 224.115 88.1435 224.115 90.8871V95.294C224.115 99.0529 224.763 102.239 226.058 104.853C227.375 107.446 229.2 109.422 231.532 110.783C233.864 112.123 236.573 112.792 239.661 112.792C241.669 112.792 243.482 112.511 245.102 111.95C246.743 111.366 248.157 110.502 249.344 109.357C250.532 108.191 251.449 106.743 252.097 105.015L259.481 107.089C258.704 109.595 257.398 111.799 255.562 113.7C253.727 115.579 251.46 117.048 248.761 118.107C246.062 119.143 243.029 119.662 239.661 119.662Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M286.524 119.792C283.372 119.792 280.511 119.197 277.941 118.009C275.372 116.8 273.332 115.061 271.82 112.792C270.309 110.502 269.553 107.737 269.553 104.497C269.553 101.645 270.115 99.3337 271.237 97.5623C272.36 95.7693 273.861 94.3651 275.739 93.3498C277.618 92.3345 279.69 91.5784 281.957 91.0815C284.246 90.563 286.545 90.1526 288.856 89.8501C291.878 89.4613 294.329 89.1697 296.207 88.9752C298.107 88.7592 299.489 88.4028 300.353 87.9059C301.238 87.409 301.681 86.5449 301.681 85.3136V85.0543C301.681 81.8571 300.806 79.3728 299.057 77.6014C297.33 75.83 294.707 74.9442 291.187 74.9442C287.539 74.9442 284.678 75.7435 282.605 77.3421C280.532 78.9408 279.075 80.6474 278.233 82.462L270.978 79.8697C272.274 76.8453 274.001 74.4906 276.16 72.8056C278.341 71.099 280.716 69.9108 283.285 69.2411C285.876 68.5498 288.424 68.2042 290.928 68.2042C292.526 68.2042 294.361 68.3986 296.434 68.7875C298.528 69.1547 300.547 69.9216 302.49 71.0882C304.455 72.2547 306.085 74.0153 307.381 76.37C308.676 78.7247 309.324 81.8787 309.324 85.832V118.625H301.681V111.885H301.292C300.774 112.965 299.91 114.121 298.701 115.352C297.492 116.584 295.883 117.631 293.875 118.495C291.868 119.359 289.417 119.792 286.524 119.792ZM287.69 112.922C290.712 112.922 293.26 112.328 295.333 111.14C297.427 109.951 299.003 108.418 300.061 106.538C301.141 104.659 301.681 102.682 301.681 100.608V93.609C301.357 93.9979 300.644 94.3543 299.543 94.6783C298.464 94.9808 297.211 95.2508 295.786 95.4885C294.383 95.7045 293.012 95.8989 291.673 96.0717C290.356 96.223 289.287 96.3526 288.467 96.4606C286.481 96.7198 284.624 97.1411 282.897 97.7243C281.191 98.286 279.809 99.1393 278.751 100.284C277.715 101.408 277.197 102.941 277.197 104.886C277.197 107.543 278.179 109.552 280.144 110.913C282.13 112.252 284.645 112.922 287.69 112.922Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M323.274 118.625V68.8523H330.658V76.37H331.176C332.083 73.9073 333.724 71.9091 336.099 70.3753C338.474 68.8415 341.151 68.0746 344.131 68.0746C344.692 68.0746 345.394 68.0854 346.236 68.107C347.078 68.1286 347.715 68.161 348.147 68.2042V75.9812C347.888 75.9164 347.294 75.8192 346.366 75.6895C345.459 75.5383 344.498 75.4627 343.483 75.4627C341.065 75.4627 338.906 75.9704 337.006 76.9857C335.128 77.9794 333.638 79.362 332.537 81.1334C331.457 82.8833 330.917 84.8815 330.917 87.1282V118.625H323.274Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M375.902 119.662C371.238 119.662 367.223 118.56 363.854 116.357C360.486 114.153 357.895 111.118 356.082 107.251C354.268 103.384 353.361 98.9665 353.361 93.9979C353.361 88.9428 354.29 84.4819 356.146 80.615C358.025 76.7265 360.637 73.6913 363.984 71.5094C367.352 69.3059 371.282 68.2042 375.772 68.2042C379.27 68.2042 382.422 68.8523 385.229 70.1484C388.036 71.4446 390.336 73.2592 392.128 75.5923C393.92 77.9254 395.032 80.6474 395.463 83.7582H387.82C387.237 81.4899 385.942 79.4808 383.934 77.731C381.947 75.9596 379.27 75.0739 375.902 75.0739C372.922 75.0739 370.31 75.8516 368.065 77.407C365.841 78.9408 364.103 81.1118 362.85 83.9202C361.62 86.7069 361.004 89.9798 361.004 93.7386C361.004 97.5839 361.609 100.932 362.818 103.784C364.049 106.635 365.776 108.85 368 110.427C370.245 112.004 372.879 112.792 375.902 112.792C377.888 112.792 379.691 112.447 381.311 111.755C382.93 111.064 384.301 110.07 385.424 108.774C386.546 107.478 387.345 105.923 387.82 104.108H395.463C395.032 107.046 393.963 109.692 392.257 112.047C390.573 114.38 388.338 116.238 385.553 117.62C382.79 118.981 379.572 119.662 375.902 119.662Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<path d="M414.28 88.6836V118.625H406.637V52.2614H414.28V76.6293H414.928C416.094 74.0585 417.842 72.0171 420.174 70.5049C422.528 68.9711 425.658 68.2042 429.566 68.2042C432.956 68.2042 435.925 68.8847 438.472 70.2456C441.02 71.585 442.996 73.6481 444.399 76.4348C445.824 79.2 446.537 82.7212 446.537 86.9986V118.625H438.894V87.517C438.894 83.5637 437.868 80.507 435.817 78.3467C433.787 76.1648 430.97 75.0739 427.364 75.0739C424.859 75.0739 422.614 75.6031 420.628 76.6617C418.663 77.7202 417.108 79.2648 415.964 81.2955C414.841 83.3261 414.28 85.7888 414.28 88.6836Z" stroke="#0500E3" stroke-width="4" mask="url(#path-5-outside-1_293_10)"/>
<defs>
<linearGradient id="paint0_linear_293_10" x1="72.96" y1="0" x2="72.96" y2="146" gradientUnits="userSpaceOnUse">
<stop stop-color="#0400C5"/>
<stop offset="1" stop-color="#15009A"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -64,7 +64,7 @@
</main>
<footer>
<p>
{{ _('Powered by') }} <a href="{{ url_for('info', pagename='about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, open metasearch engine') }}<br>
{{ _('Powered by') }} <a href="{{ url_for('info', pagename='about') }}">SearXNG</a> - {{ searx_version }} — {{ _('a privacy-respecting, open metasearch engine') }}<br>
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a>
| <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a>
{% if enable_metrics %}| <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a>{% endif %}

View file

@ -7,35 +7,35 @@ template. This file from:
{%-
set catalog = {
'alert' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M256 80c-8.66 0-16.58 7.36-16 16l8 216a8 8 0 008 8h0a8 8 0 008-8l8-216c.58-8.64-7.34-16-16-16z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><circle cx="256" cy="416" r="16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'appstore' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><rect x="64" y="64" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="216" y="64" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="368" y="64" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="64" y="216" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="216" y="216" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="368" y="216" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="64" y="368" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="216" y="368" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><rect x="368" y="368" width="80" height="80" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/></svg>',
'book' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M256 160c16-63.16 76.43-95.41 208-96a15.94 15.94 0 0116 16v288a16 16 0 01-16 16c-128 0-177.45 25.81-208 64-30.37-38-80-64-208-64-9.88 0-16-8.05-16-17.93V80a15.94 15.94 0 0116-16c131.57.59 192 32.84 208 96zM256 160v288" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'close' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M368 368L144 144M368 144L144 368"/></svg>',
'download' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M336 176h40a40 40 0 0140 40v208a40 40 0 01-40 40H136a40 40 0 01-40-40V216a40 40 0 0140-40h40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M176 272l80 80 80-80M256 48v288"/></svg>',
'ellipsis-vertical' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><circle cx="256" cy="256" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><circle cx="256" cy="416" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><circle cx="256" cy="96" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/></svg>',
'file-tray-full' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M384 80H128c-26 0-43 14-48 40L48 272v112a48.14 48.14 0 0048 48h320a48.14 48.14 0 0048-48V272l-32-152c-5-27-23-40-48-40z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M48 272h144M320 272h144M192 272a64 64 0 00128 0M144 144h224M128 208h256"/></svg>',
'film' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><rect x="48" y="96" width="416" height="320" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="384" y="336" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="384" y="256" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="384" y="176" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="384" y="96" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="48" y="336" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="48" y="256" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="48" y="176" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="48" y="96" width="80" height="80" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="128" y="96" width="256" height="160" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><rect x="128" y="256" width="256" height="160" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/></svg>',
'globe' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M256 48C141.13 48 48 141.13 48 256s93.13 208 208 208 208-93.13 208-208S370.87 48 256 48z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path d="M256 48c-58.07 0-112.67 93.13-112.67 208S197.93 464 256 464s112.67-93.13 112.67-208S314.07 48 256 48z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path d="M117.33 117.33c38.24 27.15 86.38 43.34 138.67 43.34s100.43-16.19 138.67-43.34M394.67 394.67c-38.24-27.15-86.38-43.34-138.67-43.34s-100.43 16.19-138.67 43.34" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32" d="M256 48v416M464 256H48"/></svg>',
'heart' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M352.92 80C288 80 256 144 256 144s-32-64-96.92-64c-52.76 0-94.54 44.14-95.08 96.81-1.1 109.33 86.73 187.08 183 252.42a16 16 0 0018 0c96.26-65.34 184.09-143.09 183-252.42-.54-52.67-42.32-96.81-95.08-96.81z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'image' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><rect x="48" y="80" width="416" height="352" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><circle cx="336" cy="176" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path d="M304 335.79l-90.66-90.49a32 32 0 00-43.87-1.3L48 352M224 432l123.34-123.34a32 32 0 0143.11-2L464 368" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'layers' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M434.8 137.65l-149.36-68.1c-16.19-7.4-42.69-7.4-58.88 0L77.3 137.65c-17.6 8-17.6 21.09 0 29.09l148 67.5c16.89 7.7 44.69 7.7 61.58 0l148-67.5c17.52-8 17.52-21.1-.08-29.09zM160 308.52l-82.7 37.11c-17.6 8-17.6 21.1 0 29.1l148 67.5c16.89 7.69 44.69 7.69 61.58 0l148-67.5c17.6-8 17.6-21.1 0-29.1l-79.94-38.47" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M160 204.48l-82.8 37.16c-17.6 8-17.6 21.1 0 29.1l148 67.49c16.89 7.7 44.69 7.7 61.58 0l148-67.49c17.7-8 17.7-21.1.1-29.1L352 204.48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'leecher' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M112 268l144 144 144-144M256 392V100"/></svg>',
'location' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M256 48c-79.5 0-144 61.39-144 137 0 87 96 224.87 131.25 272.49a15.77 15.77 0 0025.5 0C304 409.89 400 272.07 400 185c0-75.61-64.5-137-144-137z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><circle cx="256" cy="192" r="48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'magnet' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M421.83 293.82A144 144 0 00218.18 90.17M353.94 225.94a48 48 0 00-67.88-67.88" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M192 464v-48M90.18 421.82l33.94-33.94M48 320h48"/><path d="M286.06 158.06L172.92 271.19a32 32 0 01-45.25 0L105 248.57a32 32 0 010-45.26L218.18 90.17M421.83 293.82L308.69 407a32 32 0 01-45.26 0l-22.62-22.63a32 32 0 010-45.26l113.13-113.17M139.6 169.98l67.88 67.89M275.36 305.75l67.89 67.88" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/></svg>',
'musical-notes' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M192 218v-6c0-14.84 10-27 24.24-30.59l174.59-46.68A20 20 0 01416 154v22" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M416 295.94v80c0 13.91-8.93 25.59-22 30l-22 8c-25.9 8.72-52-10.42-52-38h0a33.37 33.37 0 0123-32l51-18.15c13.07-4.4 22-15.94 22-29.85V58a10 10 0 00-12.6-9.61L204 102a16.48 16.48 0 00-12 16v226c0 13.91-8.93 25.6-22 30l-52 18c-13.88 4.68-22 17.22-22 32h0c0 27.58 26.52 46.55 52 38l22-8c13.07-4.4 22-16.08 22-30v-80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'navigate-down' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M112 184l144 144 144-144"/></svg>',
'navigate-left' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M328 112L184 256l144 144"/></svg>',
'navigate-right' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M184 112l144 144-144 144"/></svg>',
'navigate-up' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48" d="M112 328l144-144 144 144"/></svg>',
'people' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M402 168c-2.93 40.67-33.1 72-66 72s-63.12-31.32-66-72c-3-42.31 26.37-72 66-72s69 30.46 66 72z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M336 304c-65.17 0-127.84 32.37-143.54 95.41-2.08 8.34 3.15 16.59 11.72 16.59h263.65c8.57 0 13.77-8.25 11.72-16.59C463.85 335.36 401.18 304 336 304z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path d="M200 185.94c-2.34 32.48-26.72 58.06-53 58.06s-50.7-25.57-53-58.06C91.61 152.15 115.34 128 147 128s55.39 24.77 53 57.94z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M206 306c-18.05-8.27-37.93-11.45-59-11.45-52 0-102.1 25.85-114.65 76.2-1.65 6.66 2.53 13.25 9.37 13.25H154" fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32"/></svg>',
'play' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M112 111v290c0 17.44 17 28.52 31 20.16l247.9-148.37c12.12-7.25 12.12-26.33 0-33.58L143 90.84c-14-8.36-31 2.72-31 20.16z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/></svg>',
'radio' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><circle cx="256" cy="256.02" r="32"/><path d="M184.25 192.25a96 96 0 000 127.52M327.77 319.77a96 96 0 000-127.52M133.28 141.28a168 168 0 000 229.44M378.72 370.72a168 168 0 000-229.44M435 416a240.34 240.34 0 000-320M77 96a240.34 240.34 0 000 320" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'save' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M380.93 57.37A32 32 0 00358.3 48H94.22A46.21 46.21 0 0048 94.22v323.56A46.21 46.21 0 0094.22 464h323.56A46.36 46.36 0 00464 417.78V153.7a32 32 0 00-9.37-22.63zM256 416a64 64 0 1164-64 63.92 63.92 0 01-64 64zm48-224H112a16 16 0 01-16-16v-64a16 16 0 0116-16h192a16 16 0 0116 16v64a16 16 0 01-16 16z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'school' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M32 192L256 64l224 128-224 128L32 192z"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M112 240v128l144 80 144-80V240M480 368V192M256 320v128"/></svg>',
'search' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M221.09 64a157.09 157.09 0 10157.09 157.09A157.1 157.1 0 00221.09 64z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M338.29 338.29L448 448"/></svg>',
'seeder' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M464 208L352 96 240 208M352 113.13V416M48 304l112 112 112-112M160 398V96"/></svg>',
'settings' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M262.29 192.31a64 64 0 1057.4 57.4 64.13 64.13 0 00-57.4-57.4zM416.39 256a154.34 154.34 0 01-1.53 20.79l45.21 35.46a10.81 10.81 0 012.45 13.75l-42.77 74a10.81 10.81 0 01-13.14 4.59l-44.9-18.08a16.11 16.11 0 00-15.17 1.75A164.48 164.48 0 01325 400.8a15.94 15.94 0 00-8.82 12.14l-6.73 47.89a11.08 11.08 0 01-10.68 9.17h-85.54a11.11 11.11 0 01-10.69-8.87l-6.72-47.82a16.07 16.07 0 00-9-12.22 155.3 155.3 0 01-21.46-12.57 16 16 0 00-15.11-1.71l-44.89 18.07a10.81 10.81 0 01-13.14-4.58l-42.77-74a10.8 10.8 0 012.45-13.75l38.21-30a16.05 16.05 0 006-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 00-6.07-13.94l-38.19-30A10.81 10.81 0 0149.48 186l42.77-74a10.81 10.81 0 0113.14-4.59l44.9 18.08a16.11 16.11 0 0015.17-1.75A164.48 164.48 0 01187 111.2a15.94 15.94 0 008.82-12.14l6.73-47.89A11.08 11.08 0 01213.23 42h85.54a11.11 11.11 0 0110.69 8.87l6.72 47.82a16.07 16.07 0 009 12.22 155.3 155.3 0 0121.46 12.57 16 16 0 0015.11 1.71l44.89-18.07a10.81 10.81 0 0113.14 4.58l42.77 74a10.8 10.8 0 01-2.45 13.75l-38.21 30a16.05 16.05 0 00-6.05 14.08c.33 4.14.55 8.3.55 12.47z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/></svg>',
'tv' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><rect x="32" y="96" width="448" height="272" rx="32.14" ry="32.14" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><path stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M128 416h256"/></svg>',
'alert' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M256 80c-8.66 0-16.58 7.36-16 16l8 216a8 8 0 0 0 8 8h0a8 8 0 0 0 8-8l8-216c.58-8.64-7.34-16-16-16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><circle cx="256" cy="416" r="16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'appstore' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><rect width="80" height="80" x="64" y="64" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="216" y="64" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="368" y="64" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="64" y="216" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="216" y="216" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="368" y="216" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="64" y="368" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="216" y="368" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><rect width="80" height="80" x="368" y="368" rx="40" ry="40" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'book' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M256 160c16-63.16 76.43-95.41 208-96a15.94 15.94 0 0 1 16 16v288a16 16 0 0 1-16 16c-128 0-177.45 25.81-208 64-30.37-38-80-64-208-64-9.88 0-16-8.05-16-17.93V80a15.94 15.94 0 0 1 16-16c131.57.59 192 32.84 208 96M256 160v288" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'close' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M368 368 144 144M368 144 144 368" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'download' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M336 176h40a40 40 0 0 1 40 40v208a40 40 0 0 1-40 40H136a40 40 0 0 1-40-40V216a40 40 0 0 1 40-40h40" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="m176 272 80 80 80-80M256 48v288" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'ellipsis-vertical' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><circle cx="256" cy="256" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><circle cx="256" cy="416" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><circle cx="256" cy="96" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'file-tray-full' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M384 80H128c-26 0-43 14-48 40L48 272v112a48.14 48.14 0 0 0 48 48h320a48.14 48.14 0 0 0 48-48V272l-32-152c-5-27-23-40-48-40Z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><path d="M48 272h144M320 272h144M192 272a64 64 0 0 0 128 0M144 144h224M128 208h256" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'film' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><rect width="416" height="320" x="48" y="96" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="384" y="336" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="384" y="256" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="384" y="176" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="384" y="96" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="48" y="336" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="48" y="256" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="48" y="176" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="80" height="80" x="48" y="96" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="256" height="160" x="128" y="96" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><rect width="256" height="160" x="128" y="256" rx="28" ry="28" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/></svg>',
'globe' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M256 48C141.13 48 48 141.13 48 256s93.13 208 208 208 208-93.13 208-208S370.87 48 256 48Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M256 48c-58.07 0-112.67 93.13-112.67 208S197.93 464 256 464s112.67-93.13 112.67-208S314.07 48 256 48Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M117.33 117.33c38.24 27.15 86.38 43.34 138.67 43.34s100.43-16.19 138.67-43.34M394.67 394.67c-38.24-27.15-86.38-43.34-138.67-43.34s-100.43 16.19-138.67 43.34" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M256 48v416M464 256H48" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'heart' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M352.92 80C288 80 256 144 256 144s-32-64-96.92-64c-52.76 0-94.54 44.14-95.08 96.81-1.1 109.33 86.73 187.08 183 252.42a16 16 0 0 0 18 0c96.26-65.34 184.09-143.09 183-252.42-.54-52.67-42.32-96.81-95.08-96.81" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'image' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><rect width="416" height="352" x="48" y="80" rx="48" ry="48" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><circle cx="336" cy="176" r="32" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="m304 335.79-90.66-90.49a32 32 0 0 0-43.87-1.3L48 352M224 432l123.34-123.34a32 32 0 0 1 43.11-2L464 368" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'layers' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="m434.8 137.65-149.36-68.1c-16.19-7.4-42.69-7.4-58.88 0L77.3 137.65c-17.6 8-17.6 21.09 0 29.09l148 67.5c16.89 7.7 44.69 7.7 61.58 0l148-67.5c17.52-8 17.52-21.1-.08-29.09M160 308.52l-82.7 37.11c-17.6 8-17.6 21.1 0 29.1l148 67.5c16.89 7.69 44.69 7.69 61.58 0l148-67.5c17.6-8 17.6-21.1 0-29.1l-79.94-38.47" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="m160 204.48-82.8 37.16c-17.6 8-17.6 21.1 0 29.1l148 67.49c16.89 7.7 44.69 7.7 61.58 0l148-67.49c17.7-8 17.7-21.1.1-29.1L352 204.48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'leecher' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="m112 268 144 144 144-144M256 392V100" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>',
'location' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M256 48c-79.5 0-144 61.39-144 137 0 87 96 224.87 131.25 272.49a15.77 15.77 0 0 0 25.5 0C304 409.89 400 272.07 400 185c0-75.61-64.5-137-144-137" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><circle cx="256" cy="192" r="48" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'magnet' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M421.83 293.82A144 144 0 0 0 218.18 90.17" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M353.94 225.94a48 48 0 0 0-67.88-67.88" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M192 464v-48M90.18 421.82l33.94-33.94M48 320h48" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32px"/><path d="M286.06 158.06 172.92 271.19a32 32 0 0 1-45.25 0L105 248.57a32 32 0 0 1 0-45.26L218.18 90.17M421.83 293.82 308.69 407a32 32 0 0 1-45.26 0l-22.62-22.63a32 32 0 0 1 0-45.26l113.13-113.17M139.6 169.98l67.88 67.89M275.36 305.75l67.89 67.88" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/></svg>',
'musical-notes' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M192 218v-6c0-14.84 10-27 24.24-30.59l174.59-46.68A20 20 0 0 1 416 154v22" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M416 295.94v80c0 13.91-8.93 25.59-22 30l-22 8c-25.9 8.72-52-10.42-52-38h0a33.37 33.37 0 0 1 23-32l51-18.15c13.07-4.4 22-15.94 22-29.85V58a10 10 0 0 0-12.6-9.61L204 102a16.48 16.48 0 0 0-12 16v226c0 13.91-8.93 25.6-22 30l-52 18c-13.88 4.68-22 17.22-22 32h0c0 27.58 26.52 46.55 52 38l22-8c13.07-4.4 22-16.08 22-30v-80" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'navigate-down' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="m112 184 144 144 144-144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>',
'navigate-left' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M328 112 184 256l144 144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>',
'navigate-right' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="m184 112 144 144-144 144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>',
'navigate-up' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="m112 328 144-144 144 144" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="48px"/></svg>',
'people' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M402 168c-2.93 40.67-33.1 72-66 72s-63.12-31.32-66-72c-3-42.31 26.37-72 66-72s69 30.46 66 72" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M336 304c-65.17 0-127.84 32.37-143.54 95.41-2.08 8.34 3.15 16.59 11.72 16.59h263.65c8.57 0 13.77-8.25 11.72-16.59C463.85 335.36 401.18 304 336 304Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M200 185.94c-2.34 32.48-26.72 58.06-53 58.06s-50.7-25.57-53-58.06C91.61 152.15 115.34 128 147 128s55.39 24.77 53 57.94" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M206 306c-18.05-8.27-37.93-11.45-59-11.45-52 0-102.1 25.85-114.65 76.2-1.65 6.66 2.53 13.25 9.37 13.25H154" fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'play' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M112 111v290c0 17.44 17 28.52 31 20.16l247.9-148.37c12.12-7.25 12.12-26.33 0-33.58L143 90.84c-14-8.36-31 2.72-31 20.16Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'radio' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><circle cx="256" cy="256.02" r="32"/><path d="M184.25 192.25a96 96 0 0 0 0 127.52M327.77 319.77a96 96 0 0 0 0-127.52M133.28 141.28a168 168 0 0 0 0 229.44M378.72 370.72a168 168 0 0 0 0-229.44" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M435 416a240.34 240.34 0 0 0 0-320M77 96a240.34 240.34 0 0 0 0 320" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'save' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M380.93 57.37A32 32 0 0 0 358.3 48H94.22A46.21 46.21 0 0 0 48 94.22v323.56A46.21 46.21 0 0 0 94.22 464h323.56A46.36 46.36 0 0 0 464 417.78V153.7a32 32 0 0 0-9.37-22.63ZM256 416a64 64 0 1 1 64-64 63.92 63.92 0 0 1-64 64m48-224H112a16 16 0 0 1-16-16v-64a16 16 0 0 1 16-16h192a16 16 0 0 1 16 16v64a16 16 0 0 1-16 16" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'school' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M32 192 256 64l224 128-224 128z" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/><path d="M112 240v128l144 80 144-80V240M480 368V192M256 320v128" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'search' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M221.09 64a157.09 157.09 0 1 0 157.09 157.09A157.1 157.1 0 0 0 221.09 64Z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32px"/><path d="M338.29 338.29 448 448" fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'seeder' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M464 208 352 96 240 208M352 113.13V416M48 304l112 112 112-112M160 398V96" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'settings' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><path d="M262.29 192.31a64 64 0 1 0 57.4 57.4 64.13 64.13 0 0 0-57.4-57.4M416.39 256a154 154 0 0 1-1.53 20.79l45.21 35.46a10.81 10.81 0 0 1 2.45 13.75l-42.77 74a10.81 10.81 0 0 1-13.14 4.59l-44.9-18.08a16.11 16.11 0 0 0-15.17 1.75A164.5 164.5 0 0 1 325 400.8a15.94 15.94 0 0 0-8.82 12.14l-6.73 47.89a11.08 11.08 0 0 1-10.68 9.17h-85.54a11.11 11.11 0 0 1-10.69-8.87l-6.72-47.82a16.07 16.07 0 0 0-9-12.22 155 155 0 0 1-21.46-12.57 16 16 0 0 0-15.11-1.71l-44.89 18.07a10.81 10.81 0 0 1-13.14-4.58l-42.77-74a10.8 10.8 0 0 1 2.45-13.75l38.21-30a16.05 16.05 0 0 0 6-14.08c-.36-4.17-.58-8.33-.58-12.5s.21-8.27.58-12.35a16 16 0 0 0-6.07-13.94l-38.19-30A10.81 10.81 0 0 1 49.48 186l42.77-74a10.81 10.81 0 0 1 13.14-4.59l44.9 18.08a16.11 16.11 0 0 0 15.17-1.75A164.5 164.5 0 0 1 187 111.2a15.94 15.94 0 0 0 8.82-12.14l6.73-47.89A11.08 11.08 0 0 1 213.23 42h85.54a11.11 11.11 0 0 1 10.69 8.87l6.72 47.82a16.07 16.07 0 0 0 9 12.22 155 155 0 0 1 21.46 12.57 16 16 0 0 0 15.11 1.71l44.89-18.07a10.81 10.81 0 0 1 13.14 4.58l42.77 74a10.8 10.8 0 0 1-2.45 13.75l-38.21 30a16.05 16.05 0 0 0-6.05 14.08c.33 4.14.55 8.3.55 12.47" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32px"/></svg>',
'tv' : '<svg viewBox="0 0 512 512" class="ionicon __jinja_class_placeholder__" aria-hidden="true"><rect width="448" height="272" x="32" y="96" rx="32.14" ry="32.14" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32px"/><path d="M128 416h256" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32px"/></svg>',
'information-circle' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M248 64C146.39 64 64 146.39 64 248s82.39 184 184 184 184-82.39 184-184S349.61 64 248 64z" fill="none" stroke="currentColor" stroke-miterlimit="10" stroke-width="32"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32" d="M220 220h32v116"/><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M208 340h88"/><path d="M248 130a26 26 0 1026 26 26 26 0 00-26-26z" fill="currentColor" stroke="currentColor" stroke-miterlimit="10" stroke-width="1"/></svg>',
'newspaper' : '<svg viewBox="0 0 512 512" aria-hidden="true" class="__jinja_class_placeholder__"><path d="M368 415.86V72a24.07 24.07 0 00-24-24H72a24.07 24.07 0 00-24 24v352a40.12 40.12 0 0040 40h328" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><path d="M416 464h0a48 48 0 01-48-48V128h72a24 24 0 0124 24v264a48 48 0 01-48 48z" fill="none" stroke="currentColor" stroke-linejoin="round" stroke-width="32"/><path d="M240 128h64M240 192h64M112 256h192M112 320h192M112 384h192" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="32"/><path d="M176 208h-64a16 16 0 01-16-16v-64a16 16 0 0116-16h64a16 16 0 0116 16v64a16 16 0 01-16 16z" fill="currentColor" stroke="currentColor" stroke-linejoin="round" stroke-width="1"/></svg>',
}

View file

@ -44,10 +44,10 @@
{%- endmacro -%}
<!-- Draw result sub footer -->
{%- macro result_sub_footer(result, proxify) -%}
{%- macro result_sub_footer(result) -%}
<div class="engines">
{% for engine in result.engines %}<span>{{ engine }}</span>{% endfor %}
{{ icon_small('ellipsis-vertical') + result_link(cache_url + result.url, _('cached'), "cache_link") }}&lrm; {% if proxify and proxify_results %} {{ result_link(proxify(result.url), _('proxied'), "proxyfied_link") }} {% endif %}
{{ icon_small('ellipsis-vertical') + result_link(cache_url + result.url, _('cached'), "cache_link") }}
</div>{{- '' -}}
<div class="break"></div>{{- '' -}}
{%- endmacro -%}

View file

@ -28,5 +28,5 @@
{{- result.codelines|code_highlighter(result.code_language)|safe -}}
</div>
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{{- result_footer(result) -}}

View file

@ -14,7 +14,7 @@
{{ _('This site did not provide any description.')|safe }}
</p>
{% endif -%}
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{% if result.iframe_src -%}
<div id="result-media-{{ index }}" class="embedded-content invisible">
<iframe data-src="{{result.iframe_src}}" frameborder="0" allowfullscreen></iframe>

View file

@ -43,7 +43,7 @@
<small> <a class="btn-collapse collapsed searxng_init_map hide_if_nojs" data-target="#result-map-{{ index }}" data-btn-text-collapsed="{{ _('show map') }}" data-btn-text-not-collapsed="{{ _('hide map') }}" data-leaflet-target="osm-map-{{ index }}" data-map-lon="{{ result.longitude }}" data-map-lat="{{ result.latitude }}" {% if result.boundingbox %}data-map-boundingbox='{{ result.boundingbox|tojson|safe }}'{% endif %} {% if result.geojson %}data-map-geojson='{{ result.geojson|tojson|safe }}'{% endif %}>{{ icon_small( 'globe') }} {{ _('show map') }}</a></small>
{%- endif -%}
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{% if (result.latitude and result.longitude) or result.boundingbox -%}
<div id="result-map-{{ index }}" class="invisible"><div id="osm-map-{{ index }}" class="osm-map-box"></div></div>

View file

@ -34,5 +34,5 @@
{%- if result.html_url -%}{{ result_link(result.html_url, _('HTML')) }}{%- endif -%}
{%- if result.doi %}{{ result_link('https://www.altmetric.com/details/doi/' + result.doi, 'Altmetric') }}{% endif -%}
</p>
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{{- result_footer(result) }}

View file

@ -10,5 +10,5 @@
{{ result.content|safe }}
</p>
{% endif -%}
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{{- result_footer(result) }}

View file

@ -19,5 +19,5 @@
{%- if result.files %}{{ icon_big('file') }} <span class="badge">{{ result.files }} {{ _('Number of Files') }}</span>{%- endif -%}
</p>
{%- if result.content %}<p class="content">{{ result.content|safe }}</p>{%- endif -%}
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{{- result_footer(result) -}}

View file

@ -15,7 +15,7 @@
</p>
{% endif -%}
</p>
{{- result_sub_footer(result, proxify) -}}
{{- result_sub_footer(result) -}}
{% if result.iframe_src -%}
<div id="result-video-{{ index }}" class="embedded-video invisible">
<iframe data-src="{{result.iframe_src}}" frameborder="0" allowfullscreen></iframe>

View file

@ -9,6 +9,7 @@
<input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" tabindex="1" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}">
<button id="clear_search" type="reset" aria-label="{{ _('clear') }}" class="hide_if_nojs"><span>{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button>
<button id="send_search" type="submit" {%- if search_on_category_select -%}name="category_{{ selected_categories[0]|replace(' ', '_') }}"{%- endif -%} aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button>
<div class="autocomplete hide_if_nojs"><ul></ul></div>
</div>
</div>
{% set display_tooltip = true %}

View file

@ -5,6 +5,7 @@
<input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}">
<button id="clear_search" type="reset" aria-label="{{ _('clear') }}"><span class="hide_if_nojs">{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button>
<button id="send_search" type="submit" aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button>
<div class="autocomplete hide_if_nojs"><ul></ul></div>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show more