33 Commits

Author SHA1 Message Date
Bnyro d7e8b7cd18 [feat] engines: add cara.app engine (#6092) 2026-05-17 18:39:47 +02:00
Markus Heiser f26e450778 [fix] engine: google-news - Google pushed a frontend update (#5984)
Around March 9 - 10, 2026, Google pushed a frontend update to Google News that
completely changed the HTML structure of search results.

This is a complete overhaul of the Google News engine.

- The real URL is encoded in the "jslog" attribute.
  @SeriousConcept1134: the attribute is a base64 encoded JSON
- CEID list is updated
- The typification was pushed forward

Related:

- https://github.com/searxng/searxng/issues/5852#issuecomment-4254438184
- https://github.com/searxng/searxng/issues/5852#issuecomment-4265598833

Closes: https://github.com/searxng/searxng/issues/5852
Suggested-by: SeriousConcept1134

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-17 15:27:00 +02:00
Bnyro dce3bb69bb [chore] settings.yml: set broken engines yahoo and karmasearch to inactive 2026-05-16 16:04:36 +02:00
Bnyro de49d27846 [fix] yandex images: crashes when parsing images without fallback source (#6084) 2026-05-16 15:53:23 +02:00
Bnyro 16a7537bfd [chore] engines: remove ask.com (service was discontinued) (#6083)
Source: https://www.ask.com/
2026-05-16 15:36:47 +02:00
Markus Heiser afafca93f3 [fix] engine wikidata - fails to initialize with HTTP 403 (#6081)
In order not to be further blocked, the WIKIDATA_PROPERTIES are cached, which
drastically reduces the WD-SQL request.

BTW: improve type hints

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

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-15 16:21:47 +02:00
dependabot[bot] 240f403d93 [upd] web-client (simple): Bump the minor group (#6080)
Bumps the minor group in /client/simple with 4 updates: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [stylelint](https://github.com/stylelint/stylelint) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).

Updates `@biomejs/biome` from 2.4.14 to 2.4.15
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.15/packages/@biomejs/biome)

Updates `@types/node` from 25.6.2 to 25.8.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `stylelint` from 17.11.0 to 17.11.1
- [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/17.11.0...17.11.1)

Updates `vite` from 8.0.11 to 8.0.13
- [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/v8.0.13/packages/vite)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.15
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: "@types/node"
  dependency-version: 25.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: stylelint
  dependency-version: 17.11.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: vite
  dependency-version: 8.0.13
  dependency-type: direct:development
  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>
2026-05-15 14:19:28 +02:00
dependabot[bot] 9b30ae005b [upd] pypi: Bump the minor group with 2 updates (#6079)
Bumps the minor group with 2 updates: [selenium](https://github.com/SeleniumHQ/Selenium) and [basedpyright](https://github.com/detachhead/basedpyright).


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

Updates `basedpyright` from 1.39.3 to 1.39.4
- [Release notes](https://github.com/detachhead/basedpyright/releases)
- [Commits](https://github.com/detachhead/basedpyright/compare/v1.39.3...v1.39.4)

---
updated-dependencies:
- dependency-name: selenium
  dependency-version: 4.44.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: basedpyright
  dependency-version: 1.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
2026-05-15 11:12:57 +02:00
Arnaud Jeannin 790683bbd7 [fix] google: improve CAPTCHA detection (#5922)
- Detect HTTP 302 responses (Google redirecting to /sorry/index
  without the HTTP client following the redirect)
- Detect short HTML responses (<2000 bytes) containing "/sorry/"
  links (meta-refresh or JS redirect variants)

Instances with rotating IPs can set the `suspended_times.SearxEngineCaptcha` to
0 in the search settings [1], the next request will typically use a different
outgoing IP when rotating proxies are configured

[1] https://docs.searxng.org/admin/settings/settings_search.html
2026-05-15 09:25:13 +02:00
Bnyro 52b446b4ad [make] update searx.data.traits (#6075) 2026-05-15 08:37:11 +02:00
Bnyro 6cee4b8947 [feat] yep: add support for selecting search language (#6075) 2026-05-15 08:37:11 +02:00
Markus Heiser 8e5aa9d394 [doc] Development Quickstart: documentation of the tools (dev.env)
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-13 13:55:50 +02:00
Markus Heiser cf4d7e31c4 [mod] update_engine_traits.py: improve type annotations
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-13 13:55:50 +02:00
Markus Heiser 471f2b205f [feat] update_engine_traits.py: add option to update engines selective
Previously, `update_engine_traits.py` would fetch traits for all engines, which
is very slow and by side-effect touches engine data that are unrelated to the
engine you're currently working on.

To be faster with developing `update_engine_traits.py` supports now engine
arguments.

To test, jump into the developer environment and run the script::

    $ ./manage dev.env
    (dev.env)$ ./searxng_extra/update/update_engine_traits.py --help

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-13 13:55:50 +02:00
Markus Heiser 09829b1ccc [fix] installation instructions - launch SearXNG by python -m (#6078)
[1] https://github.com/searxng/searxng/issues/126#issuecomment-4433874986

Suggested-by: @virtadpt in [1]
2026-05-13 11:34:31 +02:00
dependabot[bot] df1f24fb7f [upd] web-client (simple): Bump the minor group (#6056)
Bumps the minor group in /client/simple with 4 updates: [@biomejs/biome](https://github.com/biomejs/biome/tree/HEAD/packages/@biomejs/biome), [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [stylelint](https://github.com/stylelint/stylelint) and [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).

Updates `@biomejs/biome` from 2.4.13 to 2.4.14
- [Release notes](https://github.com/biomejs/biome/releases)
- [Changelog](https://github.com/biomejs/biome/blob/main/packages/@biomejs/biome/CHANGELOG.md)
- [Commits](https://github.com/biomejs/biome/commits/@biomejs/biome@2.4.14/packages/@biomejs/biome)

Updates `@types/node` from 25.6.0 to 25.6.2
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `stylelint` from 17.9.1 to 17.11.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/17.9.1...17.11.0)

Updates `vite` from 8.0.10 to 8.0.11
- [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/v8.0.11/packages/vite)

---
updated-dependencies:
- dependency-name: "@biomejs/biome"
  dependency-version: 2.4.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: "@types/node"
  dependency-version: 25.6.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: minor
- dependency-name: stylelint
  dependency-version: 17.11.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
- dependency-name: vite
  dependency-version: 8.0.11
  dependency-type: direct:development
  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>
2026-05-10 15:34:19 +02:00
dependabot[bot] 0cba32c15f [upd] pypi: Bump markdown-it-py from 4.0.0 to 4.2.0 in the minor group (#6054)
Bumps the minor group with 1 update: [markdown-it-py](https://github.com/executablebooks/markdown-it-py).


Updates `markdown-it-py` from 4.0.0 to 4.2.0
- [Release notes](https://github.com/executablebooks/markdown-it-py/releases)
- [Changelog](https://github.com/executablebooks/markdown-it-py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/executablebooks/markdown-it-py/compare/v4.0.0...v4.2.0)

---
updated-dependencies:
- dependency-name: markdown-it-py
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor
2026-05-09 08:43:28 +02:00
Tommaso Colella 849e17e431 [fix] 360search: improve empty results set management and increase engine timeout (#6058) 2026-05-09 08:35:21 +02:00
github-actions[bot] d8ab61a9e0 [l10n] update translations from Weblate (#6057)
94e9ade46 - 2026-05-04 - Aindriú Mac Giolla Eoin <aindriu80@noreply.codeberg.org>
883cac081 - 2026-04-30 - alexgabi <alexgabi@noreply.codeberg.org>

Co-authored-by: searxng-bot <searxng-bot@users.noreply.github.com>
2026-05-08 14:27:49 +02:00
dependabot[bot] 7eb130b1a8 [upd] github-actions: Bump github/codeql-action from 4.35.2 to 4.35.4 (#6055)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.35.2 to 4.35.4.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/95e58e9a2cdfd71adc6e0353d5c52f41a045d225...68bde559dea0fdcac2102bfdf6230c5f70eb485e)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.35.4
  dependency-type: direct:production
  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>
2026-05-08 14:25:27 +02:00
Bnyro ef6290c8cd [furo] add some project links to the online documentation (#3408)
- add button for editing docs source on GitHub
- add links to GitHub repository and public instances (searx.space)

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-07 16:19:28 +02:00
Markus Heiser 89aa588b27 [furo] customize CSS - code.literal nowrap & improve large table layout (#3408)
The readability can be improve with the following two changes:

Slightly increase the content width to make the engine list more readable::

    .content {
      width: 52em;    /*  instead of 46em */
    }

To avoid word wrap in bang::

    p code.literal {
      text-wrap: nowrap;
    }

Sugested-by: https://github.com/searxng/searxng/pull/3408#issuecomment-2094082144
2026-05-07 16:19:28 +02:00
Markus Heiser 50626ef150 [furo] remove .. contents:: directives (#3408)
The directive creates a table of contents for the page.  However, Furo includes
a table of contents already in the sidebar.  It is, thus, recommended to
removing the `.. contents::` directive.

[1] https://github.com/pradyunsg/furo/issues/88#issuecomment-803297274

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-07 16:19:28 +02:00
Markus Heiser 2f72fc4df2 [docs] switch sphinx theme from pallets to furo (#3408)
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-07 16:19:28 +02:00
Markus Heiser 130cea600d [fix] Startpage engine fails when date field is string (not integer: TypeError) (#6053)
In order to avoid an abort with an error, type- and value- errors are catched,
the publishDate cannot then be determined, but the result item remains.

[1] https://github.com/searxng/searxng/pull/5980/changes#r3091479655

Replaces the PRs:

- https://github.com/searxng/searxng/pull/5980
- https://github.com/searxng/searxng/pull/6006

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

Suggested-by: @Bnyro [1]

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-07 14:56:14 +02:00
Markus Heiser ea63c19b27 [doc] add "SearXNG BM25 Reranker" to the list of external plugins (#6052)
[1] https://github.com/searxng/searxng/issues/6039#issuecomment-4370220040

Suggested-by: @Oaklight [1]
2026-05-07 13:11:37 +02:00
Bnyro a9909c4977 [fix] karmasearch: videos engine in wrong category 2026-05-06 22:23:09 +02:00
Fabian Freund a480560371 [fix] wikidata: crashes when querying due to missing escaping of quotation marks 2026-05-06 21:13:27 +02:00
Bnyro 330d56bba9 [mod] result templates: move iframe to macro and fix page rendering for non-YouTube links (#5960)
This PR moves the `iframe` logic into a macro, so that `videos.html` and `general.html` both can benefit from the workaround to fix YouTube results by @return42 in https://github.com/searxng/searxng/pull/5858

It also fixes that only YouTube videos contained the closing `>` after `<iframe border="0" ...`, the regression has been caused by https://github.com/searxng/searxng/pull/5858

## Why is this change important?

Currently, the page breaks if there's any non-YouTube Iframe

Here, the page ends in the middle of the results and the footer and page number selector are not visible.
2026-05-06 09:29:20 +02:00
Markus Heiser 36bcd6b551 [fix] engine: wikidata - improvement of typing (#5993)
The type checker in my IDE shut down after over 500 errors / after this
patch there are still 125 criticisms, however its an improvement and a better
starting point.

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-06 08:39:55 +02:00
Markus Heiser 8fabaf86b6 [fix] engine: wikidata - initialization fails with KeyError (#5993)
The response to QUERY_PROPERTY_NAMES has changed; fields without the `name`
field are now also returned.

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

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2026-05-06 08:39:55 +02:00
Bnyro d501b0420a [mod] yep: fix engine due to new API layout (#6048)
Apparently, YEP no longer supports images and news search.

Also, the naming of the query parameters changed a bit.

Closes: https://github.com/searxng/searxng/issues/6047
2026-05-06 08:17:19 +02:00
Sai Asish Y 0ac5254b8e [fix] mwmbl: crash if there's no result description available 2026-05-05 21:40:20 +02:00
116 changed files with 1564 additions and 1624 deletions
+1 -1
View File
@@ -41,6 +41,6 @@ jobs:
write-comment: "false" write-comment: "false"
- name: Upload SARIFs - name: Upload SARIFs
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 uses: github/codeql-action/upload-sarif@68bde559dea0fdcac2102bfdf6230c5f70eb485e # v4.35.4
with: with:
sarif_file: "./scout.sarif" sarif_file: "./scout.sarif"
+140 -151
View File
@@ -15,8 +15,8 @@
"swiped-events": "1.2.0" "swiped-events": "1.2.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.4.13", "@biomejs/biome": "2.4.15",
"@types/node": "^25.6.0", "@types/node": "^25.8.0",
"browserslist": "^4.28.2", "browserslist": "^4.28.2",
"browserslist-to-esbuild": "^2.1.1", "browserslist-to-esbuild": "^2.1.1",
"edge.js": "^6.5.0", "edge.js": "^6.5.0",
@@ -24,12 +24,12 @@
"mathjs": "^15.2.0", "mathjs": "^15.2.0",
"sharp": "~0.34.5", "sharp": "~0.34.5",
"sort-package-json": "^3.6.1", "sort-package-json": "^3.6.1",
"stylelint": "^17.9.1", "stylelint": "^17.11.1",
"stylelint-config-standard-less": "^4.1.0", "stylelint-config-standard-less": "^4.1.0",
"stylelint-prettier": "^5.0.3", "stylelint-prettier": "^5.0.3",
"svgo": "^4.0.1", "svgo": "^4.0.1",
"typescript": "~6.0.3", "typescript": "~6.0.3",
"vite": "^8.0.10", "vite": "^8.0.13",
"vite-bundle-analyzer": "^1.3.8" "vite-bundle-analyzer": "^1.3.8"
} }
}, },
@@ -69,9 +69,9 @@
} }
}, },
"node_modules/@biomejs/biome": { "node_modules/@biomejs/biome": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz",
"integrity": "sha512-gLXOwkOBBg0tr7bDsqlkIh4uFeKuMjxvqsrb1Tukww1iDmHcfr4Uu8MoQxp0Rcte+69+osRNWXwHsu/zxT6XqA==", "integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==",
"dev": true, "dev": true,
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"bin": { "bin": {
@@ -85,20 +85,20 @@
"url": "https://opencollective.com/biome" "url": "https://opencollective.com/biome"
}, },
"optionalDependencies": { "optionalDependencies": {
"@biomejs/cli-darwin-arm64": "2.4.13", "@biomejs/cli-darwin-arm64": "2.4.15",
"@biomejs/cli-darwin-x64": "2.4.13", "@biomejs/cli-darwin-x64": "2.4.15",
"@biomejs/cli-linux-arm64": "2.4.13", "@biomejs/cli-linux-arm64": "2.4.15",
"@biomejs/cli-linux-arm64-musl": "2.4.13", "@biomejs/cli-linux-arm64-musl": "2.4.15",
"@biomejs/cli-linux-x64": "2.4.13", "@biomejs/cli-linux-x64": "2.4.15",
"@biomejs/cli-linux-x64-musl": "2.4.13", "@biomejs/cli-linux-x64-musl": "2.4.15",
"@biomejs/cli-win32-arm64": "2.4.13", "@biomejs/cli-win32-arm64": "2.4.15",
"@biomejs/cli-win32-x64": "2.4.13" "@biomejs/cli-win32-x64": "2.4.15"
} }
}, },
"node_modules/@biomejs/cli-darwin-arm64": { "node_modules/@biomejs/cli-darwin-arm64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz",
"integrity": "sha512-2KImO1jhNFBa2oWConyr0x6flxbQpGKv6902uGXpYM62Xyem8U80j441SyUJ8KyngsmKbQjeIv1q2CQfDkNnYg==", "integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -113,9 +113,9 @@
} }
}, },
"node_modules/@biomejs/cli-darwin-x64": { "node_modules/@biomejs/cli-darwin-x64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz",
"integrity": "sha512-BKrJklbaFN4p1Ts4kPBczo+PkbsHQg57kmJ+vON9u2t6uN5okYHaSr7h/MutPCWQgg2lglaWoSmm+zhYW+oOkg==", "integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -130,9 +130,9 @@
} }
}, },
"node_modules/@biomejs/cli-linux-arm64": { "node_modules/@biomejs/cli-linux-arm64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz",
"integrity": "sha512-NzkUDSqfvMBrPplKgVr3aXLHZ2NEELvvF4vZxXulEylKWIGqlvNEcwUcj9OLrn75TD3lJ/GIqCVlBwd1MZCuYQ==", "integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -147,9 +147,9 @@
} }
}, },
"node_modules/@biomejs/cli-linux-arm64-musl": { "node_modules/@biomejs/cli-linux-arm64-musl": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz",
"integrity": "sha512-U5MsuBQW25dXaYtqWWSPM3P96H6Y+fHuja3TQpMNnylocHW0tEbtFTDlUj6oM+YJLntvEkQy4grBvQNUD4+RCg==", "integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -164,9 +164,9 @@
} }
}, },
"node_modules/@biomejs/cli-linux-x64": { "node_modules/@biomejs/cli-linux-x64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz",
"integrity": "sha512-Az3ZZedYRBo9EQzNnD9SxFcR1G5QsGo6VEc2hIyVPZ1rdKwee/7E9oeBBZFpE8Z44ekxsDQBqbiWGW5ShOhUSQ==", "integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -181,9 +181,9 @@
} }
}, },
"node_modules/@biomejs/cli-linux-x64-musl": { "node_modules/@biomejs/cli-linux-x64-musl": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz",
"integrity": "sha512-Z601MienRgTBDza/+u2CH3RSrWoXo9rtr8NK6A4KJzqGgfxx+H3VlyLgTJ4sRo40T3pIsqpTmiOQEvYzQvBRvQ==", "integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -198,9 +198,9 @@
} }
}, },
"node_modules/@biomejs/cli-win32-arm64": { "node_modules/@biomejs/cli-win32-arm64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz",
"integrity": "sha512-Px9PS2B5/Q183bUwy/5VHqp3J2lzdOCeVGzMpphYfl8oSa7VDCqenBdqWpy6DCy/en4Rbf/Y1RieZF6dJPcc9A==", "integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -215,9 +215,9 @@
} }
}, },
"node_modules/@biomejs/cli-win32-x64": { "node_modules/@biomejs/cli-win32-x64": {
"version": "2.4.13", "version": "2.4.15",
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.13.tgz", "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz",
"integrity": "sha512-tTcMkXyBrmHi9BfrD2VNHs/5rYIUKETqsBlYOvSAABwBkJhSDVb5e7wPukftsQbO3WzQkXe6kaztC6WtUOXSoQ==", "integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1023,9 +1023,9 @@
} }
}, },
"node_modules/@oxc-project/types": { "node_modules/@oxc-project/types": {
"version": "0.127.0", "version": "0.130.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
"integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"funding": { "funding": {
@@ -1107,9 +1107,9 @@
} }
}, },
"node_modules/@rolldown/binding-android-arm64": { "node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
"integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1124,9 +1124,9 @@
} }
}, },
"node_modules/@rolldown/binding-darwin-arm64": { "node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
"integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1141,9 +1141,9 @@
} }
}, },
"node_modules/@rolldown/binding-darwin-x64": { "node_modules/@rolldown/binding-darwin-x64": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
"integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1158,9 +1158,9 @@
} }
}, },
"node_modules/@rolldown/binding-freebsd-x64": { "node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
"integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1175,9 +1175,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm-gnueabihf": { "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
"integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
"cpu": [ "cpu": [
"arm" "arm"
], ],
@@ -1192,9 +1192,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm64-gnu": { "node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
"integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1209,9 +1209,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-arm64-musl": { "node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
"integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1226,9 +1226,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-ppc64-gnu": { "node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
"integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
"cpu": [ "cpu": [
"ppc64" "ppc64"
], ],
@@ -1243,9 +1243,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-s390x-gnu": { "node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
"integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
"cpu": [ "cpu": [
"s390x" "s390x"
], ],
@@ -1260,9 +1260,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-x64-gnu": { "node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
"integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1277,9 +1277,9 @@
} }
}, },
"node_modules/@rolldown/binding-linux-x64-musl": { "node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
"integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1294,9 +1294,9 @@
} }
}, },
"node_modules/@rolldown/binding-openharmony-arm64": { "node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
"integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1311,9 +1311,9 @@
} }
}, },
"node_modules/@rolldown/binding-wasm32-wasi": { "node_modules/@rolldown/binding-wasm32-wasi": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
"integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
"cpu": [ "cpu": [
"wasm32" "wasm32"
], ],
@@ -1330,9 +1330,9 @@
} }
}, },
"node_modules/@rolldown/binding-win32-arm64-msvc": { "node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
"integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
"cpu": [ "cpu": [
"arm64" "arm64"
], ],
@@ -1347,9 +1347,9 @@
} }
}, },
"node_modules/@rolldown/binding-win32-x64-msvc": { "node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
"integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
"cpu": [ "cpu": [
"x64" "x64"
], ],
@@ -1364,9 +1364,9 @@
} }
}, },
"node_modules/@rolldown/pluginutils": { "node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
"integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -1511,9 +1511,9 @@
} }
}, },
"node_modules/@tybys/wasm-util": { "node_modules/@tybys/wasm-util": {
"version": "0.10.1", "version": "0.10.2",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"optional": true, "optional": true,
@@ -1522,13 +1522,13 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "25.6.0", "version": "25.8.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz",
"integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~7.19.0" "undici-types": ">=7.24.0 <7.24.7"
} }
}, },
"node_modules/@types/pluralize": { "node_modules/@types/pluralize": {
@@ -2434,9 +2434,9 @@
} }
}, },
"node_modules/get-east-asian-width": { "node_modules/get-east-asian-width": {
"version": "1.5.0", "version": "1.6.0",
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
"integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -2747,16 +2747,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/is-plain-object": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-what": { "node_modules/is-what": {
"version": "4.1.16", "version": "4.1.16",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
@@ -3475,9 +3465,9 @@
} }
}, },
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.10", "version": "8.5.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -3741,14 +3731,14 @@
} }
}, },
"node_modules/rolldown": { "node_modules/rolldown": {
"version": "1.0.0-rc.17", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
"integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@oxc-project/types": "=0.127.0", "@oxc-project/types": "=0.130.0",
"@rolldown/pluginutils": "1.0.0-rc.17" "@rolldown/pluginutils": "^1.0.0"
}, },
"bin": { "bin": {
"rolldown": "bin/cli.mjs" "rolldown": "bin/cli.mjs"
@@ -3757,21 +3747,21 @@
"node": "^20.19.0 || >=22.12.0" "node": "^20.19.0 || >=22.12.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@rolldown/binding-android-arm64": "1.0.0-rc.17", "@rolldown/binding-android-arm64": "1.0.1",
"@rolldown/binding-darwin-arm64": "1.0.0-rc.17", "@rolldown/binding-darwin-arm64": "1.0.1",
"@rolldown/binding-darwin-x64": "1.0.0-rc.17", "@rolldown/binding-darwin-x64": "1.0.1",
"@rolldown/binding-freebsd-x64": "1.0.0-rc.17", "@rolldown/binding-freebsd-x64": "1.0.1",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", "@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-gnu": "1.0.1",
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", "@rolldown/binding-linux-arm64-musl": "1.0.1",
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-ppc64-gnu": "1.0.1",
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-s390x-gnu": "1.0.1",
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", "@rolldown/binding-linux-x64-gnu": "1.0.1",
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", "@rolldown/binding-linux-x64-musl": "1.0.1",
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", "@rolldown/binding-openharmony-arm64": "1.0.1",
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", "@rolldown/binding-wasm32-wasi": "1.0.1",
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", "@rolldown/binding-win32-arm64-msvc": "1.0.1",
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" "@rolldown/binding-win32-x64-msvc": "1.0.1"
} }
}, },
"node_modules/run-parallel": { "node_modules/run-parallel": {
@@ -4010,9 +4000,9 @@
} }
}, },
"node_modules/string-width": { "node_modules/string-width": {
"version": "8.2.0", "version": "8.2.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
"integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@@ -4059,9 +4049,9 @@
} }
}, },
"node_modules/stylelint": { "node_modules/stylelint": {
"version": "17.9.1", "version": "17.11.1",
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.9.1.tgz", "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.11.1.tgz",
"integrity": "sha512-THTmnAPJTrg/JhkTWZlSyrO+HUYMx6ELthIHeMyD2WOKqXIJUFQv2Yxn91bvUrZdbBJaW2dUuQdPST2wcQ6C3g==", "integrity": "sha512-+smN/HqVTggUx3iuAzOi9fPh8SrH+cJWlZrYVldXoJ06orWBhZ4Ue/QEp64oei6pVrAh4w3tG+Y12Vw7MbCFRQ==",
"dev": true, "dev": true,
"funding": [ "funding": [
{ {
@@ -4096,17 +4086,16 @@
"html-tags": "^5.1.0", "html-tags": "^5.1.0",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"import-meta-resolve": "^4.2.0", "import-meta-resolve": "^4.2.0",
"is-plain-object": "^5.0.0",
"mathml-tag-names": "^4.0.0", "mathml-tag-names": "^4.0.0",
"meow": "^14.1.0", "meow": "^14.1.0",
"micromatch": "^4.0.8", "micromatch": "^4.0.8",
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
"picocolors": "^1.1.1", "picocolors": "^1.1.1",
"postcss": "^8.5.9", "postcss": "^8.5.14",
"postcss-safe-parser": "^7.0.1", "postcss-safe-parser": "^7.0.1",
"postcss-selector-parser": "^7.1.1", "postcss-selector-parser": "^7.1.1",
"postcss-value-parser": "^4.2.0", "postcss-value-parser": "^4.2.0",
"string-width": "^8.2.0", "string-width": "^8.2.1",
"supports-hyperlinks": "^4.4.0", "supports-hyperlinks": "^4.4.0",
"svg-tags": "^1.0.0", "svg-tags": "^1.0.0",
"table": "^6.9.0", "table": "^6.9.0",
@@ -4478,9 +4467,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "7.19.2", "version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -4545,16 +4534,16 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/vite": { "node_modules/vite": {
"version": "8.0.10", "version": "8.0.13",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
"integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"lightningcss": "^1.32.0", "lightningcss": "^1.32.0",
"picomatch": "^4.0.4", "picomatch": "^4.0.4",
"postcss": "^8.5.10", "postcss": "^8.5.14",
"rolldown": "1.0.0-rc.17", "rolldown": "1.0.1",
"tinyglobby": "^0.2.16" "tinyglobby": "^0.2.16"
}, },
"bin": { "bin": {
@@ -4571,7 +4560,7 @@
}, },
"peerDependencies": { "peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0", "@types/node": "^20.19.0 || >=22.12.0",
"@vitejs/devtools": "^0.1.0", "@vitejs/devtools": "^0.1.18",
"esbuild": "^0.27.0 || ^0.28.0", "esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0", "jiti": ">=1.21.0",
"less": "^4.0.0", "less": "^4.0.0",
+4 -4
View File
@@ -29,8 +29,8 @@
"swiped-events": "1.2.0" "swiped-events": "1.2.0"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.4.13", "@biomejs/biome": "2.4.15",
"@types/node": "^25.6.0", "@types/node": "^25.8.0",
"browserslist": "^4.28.2", "browserslist": "^4.28.2",
"browserslist-to-esbuild": "^2.1.1", "browserslist-to-esbuild": "^2.1.1",
"edge.js": "^6.5.0", "edge.js": "^6.5.0",
@@ -38,12 +38,12 @@
"mathjs": "^15.2.0", "mathjs": "^15.2.0",
"sharp": "~0.34.5", "sharp": "~0.34.5",
"sort-package-json": "^3.6.1", "sort-package-json": "^3.6.1",
"stylelint": "^17.9.1", "stylelint": "^17.11.1",
"stylelint-config-standard-less": "^4.1.0", "stylelint-config-standard-less": "^4.1.0",
"stylelint-prettier": "^5.0.3", "stylelint-prettier": "^5.0.3",
"svgo": "^4.0.1", "svgo": "^4.0.1",
"typescript": "~6.0.3", "typescript": "~6.0.3",
"vite": "^8.0.10", "vite": "^8.0.13",
"vite-bundle-analyzer": "^1.3.8" "vite-bundle-analyzer": "^1.3.8"
} }
} }
+57
View File
@@ -0,0 +1,57 @@
.content {
width: 52em; /* instead of 46em */
}
p code.literal {
text-wrap: nowrap;
}
aside.sidebar {
border-color: lightsteelblue;
border-radius: 3pt;
}
p.sidebar-title, .sidebar p {
margin: 6pt;
}
.sidebar li,
.hlist li {
list-style-type: disclosure-closed;
}
.sphinxsidebar .current > a {
font-weight: bold;
}
/* admonitions with (rendered) reST markup examples (:class: rst-example)
*
* .. admonition:: title of the example
* :class: rst-example
* ....
*/
div.rst-example {
background-color: inherit;
margin: 0;
border-top: none;
border-right: 1px solid #ccc;
border-bottom: none;
border-left: none;
border-radius: none;
padding: 0;
}
div.rst-example > p.admonition-title {
font-family: Sans Serif;
font-style: italic;
font-size: 0.8em;
display: block;
border-bottom: 1px solid #ccc;
padding: 0.5em 1em;
text-align: right;
}
div.sphinx-tabs {
clear: both;
}
-151
View File
@@ -1,151 +0,0 @@
@import url("pocoo.css");
a, a.reference, a.footnote-reference {
color: #004b6b;
border-color: #004b6b;
}
a:hover {
color: #6d4100;
border-color: #6d4100;
}
p.version-warning {
background-color: #004b6b;
}
aside.sidebar {
background-color: whitesmoke;
border-color: lightsteelblue;
border-radius: 3pt;
}
div.sphinxsidebar p.caption {
display: none;
}
p.sidebar-title, .sidebar p {
margin: 6pt;
}
.sidebar li,
.hlist li {
list-style-type: disclosure-closed;
}
.sphinxsidebar .current > a {
font-weight: bold;
}
/* admonitions
*/
div.admonition, div.topic, nav.contents, div.toctree-wrapper {
background-color: #fafafa;
margin: 8px 0px;
padding: 1em;
border-radius: 3pt 0 0 3pt;
border-top: none;
border-right: none;
border-bottom: none;
border-left: 5pt solid #ccc;
list-style-type: disclosure-closed;
}
div.toctree-wrapper p.caption {
font-weight: normal;
font-size: 24px;
margin: 0 0 10px 0;
padding: 0;
line-height: 1;
display: inline;
}
p.admonition-title:after {
content: none;
}
.admonition.hint { border-color: #416dc0b0; }
.admonition.note { border-color: #6c856cb0; }
.admonition.tip { border-color: #85c5c2b0; }
.admonition.attention { border-color: #ecec97b0; }
.admonition.caution { border-color: #a6c677b0; }
.admonition.danger { border-color: #d46262b0; }
.admonition.important { border-color: #dfa3a3b0; }
.admonition.error { border-color: red; }
.admonition.warning { border-color: darkred; }
.admonition.admonition-generic-admonition-title {
border-color: #416dc0b0;
}
/* admonitions with (rendered) reST markup examples (:class: rst-example)
*
* .. admonition:: title of the example
* :class: rst-example
* ....
*/
div.rst-example {
background-color: inherit;
margin: 0;
border-top: none;
border-right: 1px solid #ccc;
border-bottom: none;
border-left: none;
border-radius: none;
padding: 0;
}
div.rst-example > p.admonition-title {
font-family: Sans Serif;
font-style: italic;
font-size: 0.8em;
display: block;
border-bottom: 1px solid #ccc;
padding: 0.5em 1em;
text-align: right;
}
/* code block in figures
*/
div.highlight pre {
text-align: left;
}
/* Table theme
*/
thead, tfoot {
background-color: #fff;
}
th:hover, td:hover {
background-color: #ffc;
}
thead th, tfoot th, tfoot td, tbody th {
background-color: #fffaef;
}
tbody tr:nth-child(odd) {
background-color: #fff;
}
tbody tr:nth-child(even) {
background-color: #fafafa;
}
caption {
font-family: Sans Serif;
padding: 0.5em;
margin: 0.5em 0 0.5em 0;
caption-side: top;
text-align: left;
}
div.sphinx-tabs {
clear: both;
}
-7
View File
@@ -1,7 +0,0 @@
[theme]
inherit = pocoo
stylesheet = searxng.css
[options]
touch_icon =
globaltoc_maxdepth = 5
-5
View File
@@ -4,11 +4,6 @@
Buildhosts Buildhosts
========== ==========
.. contents::
:depth: 2
:local:
:backlinks: entry
To get best results from build, it's recommend to install additional packages on To get best results from build, it's recommend to install additional packages on
build hosts (see :ref:`searxng.sh`). build hosts (see :ref:`searxng.sh`).
-5
View File
@@ -61,11 +61,6 @@ section might give you some guidance.
- `Apache Fedora`_ - `Apache Fedora`_
- `Apache directives`_ - `Apache directives`_
.. contents::
:depth: 2
:local:
:backlinks: entry
The Apache HTTP server The Apache HTTP server
====================== ======================
-6
View File
@@ -41,12 +41,6 @@ section might give you some guidance.
- `uWSGI support from nginx`_ - `uWSGI support from nginx`_
.. contents::
:depth: 2
:local:
:backlinks: entry
The nginx HTTP server The nginx HTTP server
===================== =====================
-6
View File
@@ -4,12 +4,6 @@
Step by step installation Step by step installation
========================= =========================
.. contents::
:depth: 2
:local:
:backlinks: entry
In this section we show the setup of a SearXNG instance that will be installed In this section we show the setup of a SearXNG instance that will be installed
by the :ref:`installation scripts`. by the :ref:`installation scripts`.
-6
View File
@@ -9,12 +9,6 @@ uWSGI
- `systemd.unit`_ - `systemd.unit`_
- `uWSGI Emperor`_ - `uWSGI Emperor`_
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _systemd.unit: https://www.freedesktop.org/software/systemd/man/systemd.unit.html .. _systemd.unit: https://www.freedesktop.org/software/systemd/man/systemd.unit.html
.. _One service per app in systemd: .. _One service per app in systemd:
https://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd https://uwsgi-docs.readthedocs.io/en/latest/Systemd.html#one-service-per-app-in-systemd
-6
View File
@@ -8,11 +8,6 @@ Favicons
Don't activate the favicons before reading the documentation. Don't activate the favicons before reading the documentation.
.. contents::
:depth: 2
:local:
:backlinks: entry
Activating the favicons in SearXNG is very easy, but this **generates a Activating the favicons in SearXNG is very easy, but this **generates a
significantly higher load** in the client/server communication and increases significantly higher load** in the client/server communication and increases
resources needed on the server. resources needed on the server.
@@ -250,4 +245,3 @@ into the *proxy*:
.. _data URL: .. _data URL:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs
.. _FQN: https://en.wikipedia.org/wiki/Fully_qualified_name .. _FQN: https://en.wikipedia.org/wiki/Fully_qualified_name
-5
View File
@@ -8,10 +8,5 @@ Limiter
The limiter requires a :ref:`Valkey <settings valkey>` database. The limiter requires a :ref:`Valkey <settings valkey>` database.
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.limiter .. automodule:: searx.limiter
:members: :members:
-5
View File
@@ -12,11 +12,6 @@ file.
- :ref:`use_default_settings.yml` - :ref:`use_default_settings.yml`
- :ref:`search API` - :ref:`search API`
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _settings location: .. _settings location:
settings.yml location settings.yml location
+13 -6
View File
@@ -102,11 +102,18 @@ The built-in plugins are all located in the namespace `searx.plugins`.
external plugins external plugins
================ ================
SearXNG supports :ref:`external plugins <dev plugin>` / there is no need to
install one, SearXNG runs out of the box.
`Only show green hosted results`_:
SearXNG plugin to check if a domain is part of the Green WEB.
`SearXNG BM25 Reranker`_:
SearXNG plugin that reranks search results using BM25 text relevance scoring
to improve search quality.
.. _Only show green hosted results: .. _Only show green hosted results:
https://github.com/return42/tgwf-searx-plugins/ https://github.com/return42/tgwf-searx-plugins/
SearXNG supports *external plugins* / there is no need to install one, SearXNG .. _SearXNG BM25 Reranker:
runs out of the box. https://github.com/Oaklight/searxng-bm25-reranker
- `Only show green hosted results`_
- ..
-5
View File
@@ -9,11 +9,6 @@ SearXNG maintenance
- :ref:`toolboxing` - :ref:`toolboxing`
- :ref:`uWSGI maintenance` - :ref:`uWSGI maintenance`
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _update searxng: .. _update searxng:
How to update How to update
+1 -1
View File
@@ -169,7 +169,7 @@ ${fedora_build}
$ sudo -H -u ${SERVICE_USER} -i $ sudo -H -u ${SERVICE_USER} -i
(${SERVICE_USER})$ cd ${SEARXNG_SRC} (${SERVICE_USER})$ cd ${SEARXNG_SRC}
(${SERVICE_USER})$ export SEARXNG_SETTINGS_PATH=\"${SEARXNG_SETTINGS_PATH}\" (${SERVICE_USER})$ export SEARXNG_SETTINGS_PATH=\"${SEARXNG_SETTINGS_PATH}\"
(${SERVICE_USER})$ python searx/webapp.py (${SERVICE_USER})$ python -m searx.webapp
# disable debug # disable debug
$ sudo -H sed -i -e \"s/debug : True/debug : False/g\" \"$SEARXNG_SETTINGS_PATH\" $ sudo -H sed -i -e \"s/debug : True/debug : False/g\" \"$SEARXNG_SETTINGS_PATH\"
+41 -34
View File
@@ -1,8 +1,7 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
import sys, os import os
from pathlib import Path from pathlib import Path
from pallets_sphinx_themes import ProjectLink
from searx import get_setting from searx import get_setting
from searx.version import VERSION_STRING, GIT_URL, GIT_BRANCH from searx.version import VERSION_STRING, GIT_URL, GIT_BRANCH
@@ -98,7 +97,6 @@ extlinks['pull-searx'] = ('https://github.com/searx/searx/pull/%s', 'PR %s')
extlinks['origin'] = (GIT_URL + '/blob/' + GIT_BRANCH + '/%s', 'git://%s') extlinks['origin'] = (GIT_URL + '/blob/' + GIT_BRANCH + '/%s', 'git://%s')
extlinks['patch'] = (GIT_URL + '/commit/%s', '#%s') extlinks['patch'] = (GIT_URL + '/commit/%s', '#%s')
extlinks['docs'] = (DOCS_URL + '/%s', 'docs: %s') extlinks['docs'] = (DOCS_URL + '/%s', 'docs: %s')
extlinks['pypi'] = ('https://pypi.org/project/%s', 'PyPi: %s')
extlinks['man'] = ('https://manpages.debian.org/jump?q=%s', '%s') extlinks['man'] = ('https://manpages.debian.org/jump?q=%s', '%s')
#extlinks['role'] = ( #extlinks['role'] = (
# 'https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-%s', '') # 'https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-%s', '')
@@ -117,7 +115,6 @@ extensions = [
'sphinx.ext.viewcode', 'sphinx.ext.viewcode',
"sphinx.ext.autodoc", "sphinx.ext.autodoc",
"sphinx.ext.intersphinx", "sphinx.ext.intersphinx",
"pallets_sphinx_themes",
"sphinx_issues", # https://github.com/sloria/sphinx-issues/blob/master/README.rst "sphinx_issues", # https://github.com/sloria/sphinx-issues/blob/master/README.rst
"sphinx_jinja", # https://github.com/tardyp/sphinx-jinja "sphinx_jinja", # https://github.com/tardyp/sphinx-jinja
"sphinxcontrib.programoutput", # https://github.com/NextThought/sphinxcontrib-programoutput "sphinxcontrib.programoutput", # https://github.com/NextThought/sphinxcontrib-programoutput
@@ -158,15 +155,49 @@ issues_github_path = "searxng/searxng"
# HTML ----------------------------------------------------------------- # HTML -----------------------------------------------------------------
html_theme = "furo"
html_theme_options = {
# link to project source at GitHub for editing and viewing docs code
"source_repository": "https://github.com/searxng/searxng/",
"source_branch": "master",
"source_directory": "docs/",
# Show link to repository & searx.space in footer
"footer_icons": [
{
"name": "GitHub",
"url": "https://github.com/searxng/searxng/",
"html": "&#x1F4BE;",
},
{
"name": "searx.space",
"url": "https://searx.space/",
"html": "&#x1F310;",
},
],
}
html_sidebars = {
"**": [
"sidebar/scroll-start.html",
"sidebar/brand.html",
"sidebar/search.html",
"sidebar/navigation.html",
"sidebar/ethical-ads.html",
"sidebar/scroll-end.html",
]
}
html_static_path = ['_static']
html_css_files = [
'searxng.css',
]
# https://searxng.github.io/searxng --> '/searxng/' # https://searxng.github.io/searxng --> '/searxng/'
# https://docs.searxng.org --> '/' # https://docs.searxng.org --> '/'
notfound_urls_prefix = '/' notfound_urls_prefix = '/'
sys.path.append(os.path.abspath('_themes'))
sys.path.insert(0, os.path.abspath("../"))
html_theme_path = ['_themes']
html_theme = "searxng"
# sphinx.ext.imgmath setup # sphinx.ext.imgmath setup
html_math_renderer = 'imgmath' html_math_renderer = 'imgmath'
imgmath_image_format = 'svg' imgmath_image_format = 'svg'
@@ -174,34 +205,10 @@ imgmath_font_size = 14
# sphinx.ext.imgmath setup END # sphinx.ext.imgmath setup END
html_show_sphinx = False html_show_sphinx = False
html_theme_options = {"index_sidebar_logo": True}
html_context = {"project_links": [] }
html_context["project_links"].append(ProjectLink("Source", GIT_URL + '/tree/' + GIT_BRANCH))
if WIKI_URL:
html_context["project_links"].append(ProjectLink("Wiki", WIKI_URL))
if PUBLIC_INSTANCES:
html_context["project_links"].append(ProjectLink("Public instances", PUBLIC_INSTANCES))
if ISSUE_URL:
html_context["project_links"].append(ProjectLink("Issue Tracker", ISSUE_URL))
if PRIVACYPOLICY_URL:
html_context["project_links"].append(ProjectLink("Privacy Policy", PRIVACYPOLICY_URL))
if CONTACT_URL:
html_context["project_links"].append(ProjectLink("Contact", CONTACT_URL))
html_sidebars = {
"**": [
"globaltoc.html",
"project.html",
"relations.html",
"searchbox.html",
"sourcelink.html"
],
}
singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]}
html_logo = "../client/simple/src/brand/searxng-wordmark.svg" html_logo = "../client/simple/src/brand/searxng-wordmark.svg"
html_title = "SearXNG Documentation ({})".format(VERSION_STRING) html_title = "SearXNG Documentation ({})".format(VERSION_STRING)
html_show_sourcelink = True html_show_sourcelink = True
html_copy_source = True
# LaTeX ---------------------------------------------------------------- # LaTeX ----------------------------------------------------------------
-5
View File
@@ -4,11 +4,6 @@
How to contribute How to contribute
================= =================
.. contents::
:depth: 2
:local:
:backlinks: entry
Prime directives: Privacy, Hackability Prime directives: Privacy, Hackability
====================================== ======================================
-5
View File
@@ -4,11 +4,6 @@
Demo Offline Engine Demo Offline Engine
=================== ===================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.demo_offline .. automodule:: searx.engines.demo_offline
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
Demo Online Engine Demo Online Engine
================== ==================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.demo_online .. automodule:: searx.engines.demo_online
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
Engine Overview Engine Overview
=============== ===============
.. contents::
:depth: 3
:local:
:backlinks: entry
.. _metasearch-engine: https://en.wikipedia.org/wiki/Metasearch_engine .. _metasearch-engine: https://en.wikipedia.org/wiki/Metasearch_engine
.. sidebar:: Further reading .. .. sidebar:: Further reading ..
-6
View File
@@ -4,12 +4,6 @@
Engine Implementations Engine Implementations
====================== ======================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. toctree:: .. toctree::
:caption: Framework Components :caption: Framework Components
:maxdepth: 2 :maxdepth: 2
-5
View File
@@ -4,10 +4,5 @@
JSON Engine JSON Engine
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.json_engine .. automodule:: searx.engines.json_engine
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
MediaWiki Engine MediaWiki Engine
================ ================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.mediawiki .. automodule:: searx.engines.mediawiki
:members: :members:
@@ -9,11 +9,6 @@ Command Line Engines
- :origin:`command.py <searx/engines/command.py>` - :origin:`command.py <searx/engines/command.py>`
- :ref:`offline engines` - :ref:`offline engines`
.. contents::
:depth: 2
:local:
:backlinks: entry
.. sidebar:: info .. sidebar:: info
Initial sponsored by `Search and Discovery Fund Initial sponsored by `Search and Discovery Fund
@@ -10,11 +10,6 @@ NoSQL databases
- `valkey.io <https://valkey.io/>`_ - `valkey.io <https://valkey.io/>`_
- `MongoDB <https://www.mongodb.com>`_ - `MongoDB <https://www.mongodb.com>`_
.. contents::
:depth: 2
:local:
:backlinks: entry
.. sidebar:: info .. sidebar:: info
Initial sponsored by `Search and Discovery Fund Initial sponsored by `Search and Discovery Fund
@@ -7,11 +7,6 @@ Local Search APIs
- `Comparison to alternatives - `Comparison to alternatives
<https://docs.meilisearch.com/learn/what_is_meilisearch/comparison_to_alternatives.html>`_ <https://docs.meilisearch.com/learn/what_is_meilisearch/comparison_to_alternatives.html>`_
.. contents::
:depth: 1
:local:
:backlinks: entry
.. sidebar:: info .. sidebar:: info
Initial sponsored by `Search and Discovery Fund Initial sponsored by `Search and Discovery Fund
-5
View File
@@ -10,11 +10,6 @@ SQL Engines
- `PostgreSQL <https://www.postgresql.org>`_ - `PostgreSQL <https://www.postgresql.org>`_
- `MySQL <https://www.mysql.com>`_ - `MySQL <https://www.mysql.com>`_
.. contents::
:depth: 2
:local:
:backlinks: entry
.. sidebar:: info .. sidebar:: info
Initial sponsored by `Search and Discovery Fund Initial sponsored by `Search and Discovery Fund
-5
View File
@@ -4,10 +4,5 @@
Adobe Stock Adobe Stock
=========== ===========
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.adobe_stock .. automodule:: searx.engines.adobe_stock
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Alpine Linux Packages Alpine Linux Packages
===================== =====================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.alpinelinux .. automodule:: searx.engines.alpinelinux
:members: :members:
@@ -4,10 +4,5 @@
Anna's Archive Anna's Archive
============== ==============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.annas_archive .. automodule:: searx.engines.annas_archive
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
Arch Linux Arch Linux
========== ==========
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.archlinux .. automodule:: searx.engines.archlinux
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Bing Engines Bing Engines
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _bing web engine: .. _bing web engine:
Bing WEB Bing WEB
-5
View File
@@ -4,10 +4,5 @@
Bpb Bpb
=== ===
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.bpb .. automodule:: searx.engines.bpb
:members: :members:
-5
View File
@@ -2,11 +2,6 @@
Brave Engines Brave Engines
============= =============
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
Brave offers two different engines for SearXNG: Brave offers two different engines for SearXNG:
1. The standard engine (``brave``) uses the web interface. 1. The standard engine (``brave``) uses the web interface.
-5
View File
@@ -4,11 +4,6 @@
BT4G BT4G
==== ====
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.bt4g .. automodule:: searx.engines.bt4g
:members: :members:
+8
View File
@@ -0,0 +1,8 @@
.. _cara engine:
===========
Cara Images
===========
.. automodule:: searx.engines.cara
:members:
-5
View File
@@ -4,10 +4,5 @@
CORE CORE
==== ====
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.core .. automodule:: searx.engines.core
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Dailymotion Dailymotion
=========== ===========
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.dailymotion .. automodule:: searx.engines.dailymotion
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
DuckDuckGo Engines DuckDuckGo Engines
================== ==================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.duckduckgo .. automodule:: searx.engines.duckduckgo
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Google Engines Google Engines
============== ==============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _google API: .. _google API:
Google API Google API
-5
View File
@@ -4,10 +4,5 @@
Lemmy Lemmy
===== =====
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.lemmy .. automodule:: searx.engines.lemmy
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Library of Congress Library of Congress
=================== ===================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.loc .. automodule:: searx.engines.loc
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Mastodon Mastodon
======== ========
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.mastodon .. automodule:: searx.engines.mastodon
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Moviepilot Moviepilot
========== ==========
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.moviepilot .. automodule:: searx.engines.moviepilot
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Matrix Rooms Search (MRS) Matrix Rooms Search (MRS)
========================= =========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.mrs .. automodule:: searx.engines.mrs
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Mwmbl Engine Mwmbl Engine
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _mwmbl web engine: .. _mwmbl web engine:
Mwmbl WEB Mwmbl WEB
-5
View File
@@ -4,10 +4,5 @@
Odysee Odysee
====== ======
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.odysee .. automodule:: searx.engines.odysee
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Peertube Engines Peertube Engines
================ ================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _peertube video engine: .. _peertube video engine:
Peertube Video Peertube Video
-5
View File
@@ -4,10 +4,5 @@
Piped Piped
===== =====
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.piped .. automodule:: searx.engines.piped
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Presearch Engine Presearch Engine
================ ================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.presearch .. automodule:: searx.engines.presearch
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Qwant Qwant
===== =====
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.qwant .. automodule:: searx.engines.qwant
:members: :members:
@@ -4,10 +4,5 @@
RadioBrowser RadioBrowser
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.radio_browser .. automodule:: searx.engines.radio_browser
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Recoll Engine Recoll Engine
============= =============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.recoll .. automodule:: searx.engines.recoll
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Soundcloud Soundcloud
========== ==========
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.soundcloud .. automodule:: searx.engines.soundcloud
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Startpage Engines Startpage Engines
================= =================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.startpage .. automodule:: searx.engines.startpage
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Tagesschau API Tagesschau API
============== ==============
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.tagesschau .. automodule:: searx.engines.tagesschau
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Torznab WebAPI Torznab WebAPI
============== ==============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.torznab .. automodule:: searx.engines.torznab
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Void Linux binary packages Void Linux binary packages
========================== ==========================
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.voidlinux .. automodule:: searx.engines.voidlinux
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Wallhaven Wallhaven
========= =========
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.wallhaven .. automodule:: searx.engines.wallhaven
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Wikimedia Wikimedia
========= =========
.. contents::
:depth: 2
:local:
:backlinks: entry
.. _wikipedia engine: .. _wikipedia engine:
Wikipedia Wikipedia
-5
View File
@@ -4,10 +4,5 @@
Yacy Yacy
==== ====
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.yacy .. automodule:: searx.engines.yacy
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Yahoo Engine Yahoo Engine
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.yahoo .. automodule:: searx.engines.yahoo
:members: :members:
-5
View File
@@ -4,10 +4,5 @@
Z-Library Z-Library
========= =========
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.zlibrary .. automodule:: searx.engines.zlibrary
:members: :members:
@@ -4,11 +4,6 @@
Tineye Tineye
====== ======
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.tineye .. automodule:: searx.engines.tineye
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
XPath Engine XPath Engine
============ ============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.engines.xpath .. automodule:: searx.engines.xpath
:members: :members:
-5
View File
@@ -19,11 +19,6 @@ Makefiles, we recommend to read gnu-make_ introduction.
To install developer requirements follow :ref:`buildhosts`. To install developer requirements follow :ref:`buildhosts`.
.. contents::
:depth: 2
:local:
:backlinks: entry
The usage is simple, just type ``make {target-name}`` to *build* a target. The usage is simple, just type ``make {target-name}`` to *build* a target.
Calling the ``help`` target gives a first overview (``make help``): Calling the ``help`` target gives a first overview (``make help``):
+19 -1
View File
@@ -60,11 +60,29 @@ into the developer environment and start a python based HTTP server by::
$ ./manage dev.env $ ./manage dev.env
... ...
(dev.env)$ SEARXNG_DEBUG=1 python -m searx.webapp (dev.env)$ SEARXNG_DEBUG=1 searxng-run
Since this is a pure Python solution, you can set breakpoints in your code with Since this is a pure Python solution, you can set breakpoints in your code with
``pdb.set_trace()`` and the debugger will wait for you in the terminal prompt. ``pdb.set_trace()`` and the debugger will wait for you in the terminal prompt.
Any other script or command line provided by SearXNG can also be used in the
same environment, here are a few examples::
# tools related to favicons
(dev.env)$ python -m searx.favicons
# tools related to DATA stored in searx/data
(dev.env)$ python -m searx.data --help
# tools related to engines
(dev.env)$ python -m searx.enginelib --help
# to test one of the update scripts
(dev.env)$ searxng_extra/update/update_engine_traits.py --help
# to test the update of the wikidata units
(dev.env)$ searxng_extra/update/update_wikidata_units.py
.. sidebar:: further read .. sidebar:: further read
-6
View File
@@ -36,12 +36,6 @@ docs.live <make docs.live>` to build HTML while editing.
- SVG_, ImageMagick_ - SVG_, ImageMagick_
- DOT_, `Graphviz's dot`_, Graphviz_ - DOT_, `Graphviz's dot`_, Graphviz_
.. contents::
:depth: 3
:local:
:backlinks: entry
Sphinx_ and reST_ have their place in the python ecosystem. Over that reST is Sphinx_ and reST_ have their place in the python ecosystem. Over that reST is
used in popular projects, e.g the Linux kernel documentation `[kernel doc]`_. used in popular projects, e.g the Linux kernel documentation `[kernel doc]`_.
-5
View File
@@ -14,11 +14,6 @@ type of a result is defined by the :py:obj:`result_type.Result.template`. To
set another media-type as :ref:`template default`, the field ``template`` set another media-type as :ref:`template default`, the field ``template``
in the result item must be set to the desired type. in the result item must be set to the desired type.
.. contents:: Contents
:depth: 2
:local:
:backlinks: entry
.. _result template macros: .. _result template macros:
-5
View File
@@ -7,11 +7,6 @@ Why use a private instance?
\.\.\.is a common question among SearXNG users. Before answering this \.\.\.is a common question among SearXNG users. Before answering this
question, see what options a SearXNG user has. question, see what options a SearXNG user has.
.. contents::
:depth: 2
:local:
:backlinks: entry
Public instances are open to everyone who has access to their URL. Usually, they Public instances are open to everyone who has access to their URL. Usually, they
are operated by unknown parties (from the users' point of view). Private are operated by unknown parties (from the users' point of view). Private
instances can be used by a select group of people, such as a SearXNG instance for a instances can be used by a select group of people, such as a SearXNG instance for a
-5
View File
@@ -4,11 +4,6 @@
Bot Detection Bot Detection
============= =============
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.botdetection .. automodule:: searx.botdetection
:members: :members:
-8
View File
@@ -4,11 +4,6 @@
Favicons (source) Favicons (source)
================= =================
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.favicons .. automodule:: searx.favicons
:members: :members:
@@ -43,6 +38,3 @@ Favicons Cache
.. automodule:: searx.favicons.cache .. automodule:: searx.favicons.cache
:members: :members:
-5
View File
@@ -4,11 +4,6 @@
Locales Locales
======= =======
.. contents::
:depth: 2
:local:
:backlinks: entry
.. automodule:: searx.locales .. automodule:: searx.locales
:members: :members:
-6
View File
@@ -4,12 +4,6 @@
Search processors Search processors
================= =================
.. contents::
:depth: 2
:local:
:backlinks: entry
Abstract processor class Abstract processor class
======================== ========================
-5
View File
@@ -22,11 +22,6 @@ Configured Engines
called *tabs*), engines can be queried by their name or the categories they called *tabs*), engines can be queried by their name or the categories they
belong to, by using a :ref:`\!bing syntax <search-syntax>`. belong to, by using a :ref:`\!bing syntax <search-syntax>`.
.. contents::
:depth: 2
:local:
:backlinks: entry
.. jinja:: searx .. jinja:: searx
{% for category, engines in categories_as_tabs.items() %} {% for category, engines in categories_as_tabs.items() %}
-5
View File
@@ -2,11 +2,6 @@
User information User information
================ ================
.. contents::
:depth: 3
:local:
:backlinks: entry
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2
-6
View File
@@ -15,12 +15,6 @@ script :origin:`utils/searxng.sh`.
- :ref:`installation nginx` - :ref:`installation nginx`
- :ref:`installation apache` - :ref:`installation apache`
.. contents::
:depth: 2
:local:
:backlinks: entry
Install Install
======= =======
+3 -3
View File
@@ -4,13 +4,13 @@ cov-core==1.15.0
black==25.9.0 black==25.9.0
pylint==4.0.5 pylint==4.0.5
splinter==0.21.0 splinter==0.21.0
selenium==4.43.0 selenium==4.44.0
Pallets-Sphinx-Themes==2.5.0
Sphinx==8.2.3;python_version <= "3.11" Sphinx==8.2.3;python_version <= "3.11"
Sphinx==9.1.0; python_version > "3.11" Sphinx==9.1.0; python_version > "3.11"
sphinx-issues==6.0.0 sphinx-issues==6.0.0
sphinx-jinja==2.0.2 sphinx-jinja==2.0.2
sphinx-tabs==3.5.0 sphinx-tabs==3.5.0
furo==2025.12.19
sphinxcontrib-programoutput==0.19 sphinxcontrib-programoutput==0.19
sphinx-autobuild==2025.8.25 sphinx-autobuild==2025.8.25
sphinx-notfound-page==1.1.0 sphinx-notfound-page==1.1.0
@@ -24,5 +24,5 @@ docutils>=0.21.2;python_version <= "3.11"
docutils>=0.22.4; python_version > "3.11" docutils>=0.22.4; python_version > "3.11"
parameterized==0.9.0 parameterized==0.9.0
granian[reload]==2.7.4 granian[reload]==2.7.4
basedpyright==1.39.3 basedpyright==1.39.4
types-lxml==2026.2.16 types-lxml==2026.2.16
+1 -1
View File
@@ -11,7 +11,7 @@ httpx[http2]==0.28.1
httpx-socks[asyncio]==0.10.0 httpx-socks[asyncio]==0.10.0
sniffio==1.3.1 sniffio==1.3.1
valkey==6.1.1 valkey==6.1.1
markdown-it-py==4.0.0 markdown-it-py==4.2.0
msgspec==0.21.1 msgspec==0.21.1
typer==0.25.1 typer==0.25.1
isodate==0.7.2 isodate==0.7.2
+7 -1
View File
@@ -114,7 +114,13 @@ class ExpireCacheStats:
if expire: if expire:
valid_until = datetime.datetime.fromtimestamp(expire).strftime("%Y-%m-%d %H:%M:%S") valid_until = datetime.datetime.fromtimestamp(expire).strftime("%Y-%m-%d %H:%M:%S")
c_kv += 1 c_kv += 1
lines.append(f"[{ctx_name:20s}] {valid_until} {key:12}" f" --> ({type(value).__name__}) {value} ") value_str = str(value)
if len(value_str) > 120:
value_str = f"{value_str[:120]} ..."
lines.append(
f"[{ctx_name:20s}] {valid_until} {key:12}"
f" --> ({type(value).__name__}:{len(value)}) {value_str} "
)
lines.append(f"Number of contexts: {c_ctx}") lines.append(f"Number of contexts: {c_ctx}")
lines.append(f"number of key/value pairs: {c_kv}") lines.append(f"number of key/value pairs: {c_kv}")
+178 -7
View File
@@ -4079,6 +4079,7 @@
"bg-BG": "BG:bg", "bg-BG": "BG:bg",
"bn-BD": "BD:bn", "bn-BD": "BD:bn",
"bn-IN": "IN:bn", "bn-IN": "IN:bn",
"ca-ES": "ES:ca",
"cs-CZ": "CZ:cs", "cs-CZ": "CZ:cs",
"de-AT": "AT:de", "de-AT": "AT:de",
"de-CH": "CH:de", "de-CH": "CH:de",
@@ -4110,16 +4111,15 @@
"es-CO": "CO:es-419", "es-CO": "CO:es-419",
"es-CU": "CU:es-419", "es-CU": "CU:es-419",
"es-ES": "ES:es", "es-ES": "ES:es",
"es-MX": "MX:es-419", "et-EE": "EE:et",
"es-PE": "PE:es-419", "fi-FI": "FI:fi",
"es-US": "US:es-419",
"es-VE": "VE:es-419",
"fr-BE": "BE:fr", "fr-BE": "BE:fr",
"fr-CA": "CA:fr", "fr-CA": "CA:fr",
"fr-CH": "CH:fr", "fr-CH": "CH:fr",
"fr-FR": "FR:fr", "fr-FR": "FR:fr",
"fr-MA": "MA:fr", "fr-MA": "MA:fr",
"fr-SN": "SN:fr", "fr-SN": "SN:fr",
"gu-IN": "IN:gu",
"he-IL": "IL:he", "he-IL": "IL:he",
"hi-IN": "IN:hi", "hi-IN": "IN:hi",
"hu-HU": "HU:hu", "hu-HU": "HU:hu",
@@ -4131,12 +4131,13 @@
"lv-LV": "LV:lv", "lv-LV": "LV:lv",
"ml-IN": "IN:ml", "ml-IN": "IN:ml",
"mr-IN": "IN:mr", "mr-IN": "IN:mr",
"ms-MY": "MY:ms",
"nb-NO": "NO:no", "nb-NO": "NO:no",
"nl-BE": "BE:nl", "nl-BE": "BE:nl",
"nl-NL": "NL:nl", "nl-NL": "NL:nl",
"pa-IN": "IN:pa",
"pl-PL": "PL:pl", "pl-PL": "PL:pl",
"pt-BR": "BR:pt-419", "pt-BR": "BR:pt-419",
"pt-PT": "PT:pt-150",
"ro-RO": "RO:ro", "ro-RO": "RO:ro",
"ru-RU": "RU:ru", "ru-RU": "RU:ru",
"ru-UA": "UA:ru", "ru-UA": "UA:ru",
@@ -4151,8 +4152,7 @@
"uk-UA": "UA:uk", "uk-UA": "UA:uk",
"vi-VN": "VN:vi", "vi-VN": "VN:vi",
"zh-CN": "CN:zh-Hans", "zh-CN": "CN:zh-Hans",
"zh-HK": "HK:zh-Hant", "zh-HK": "HK:zh-Hant"
"zh-TW": "TW:zh-Hant"
}, },
"supported_domains": {} "supported_domains": {}
}, },
@@ -8513,6 +8513,177 @@
"zh-classical": "zh-classical" "zh-classical": "zh-classical"
} }
}, },
"yep": {
"all_locale": null,
"custom": {},
"data_type": "traits_v1",
"languages": {
"aa": "aa",
"ab": "ab",
"af": "af",
"ak": "ak",
"am": "am",
"an": "an",
"ar": "ar",
"as": "as",
"az": "az",
"ba": "ba",
"be": "be",
"bg": "bg",
"bho": "bh",
"bm": "bm",
"bn": "bn",
"bo": "bo",
"br": "br",
"bs": "bs",
"ca": "ca",
"ce": "ce",
"co": "co",
"cs": "cs",
"cu": "cu",
"cv": "cv",
"cy": "cy",
"da": "da",
"de": "de",
"dv": "dv",
"dz": "dz",
"ee": "ee",
"el": "el",
"en": "en",
"eo": "eo",
"es": "es",
"et": "et",
"eu": "eu",
"fa": "fa",
"ff": "ff",
"fi": "fi",
"fil": "tl",
"fo": "fo",
"fr": "fr",
"fy": "fy",
"ga": "ga",
"gd": "gd",
"gl": "gl",
"gn": "gn",
"gu": "gu",
"gv": "gv",
"ha": "ha",
"he": "he",
"hi": "hi",
"hr": "hr",
"ht": "ht",
"hu": "hu",
"hy": "hy",
"ia": "ia",
"id": "id",
"ie": "ie",
"ig": "ig",
"ii": "ii",
"io": "io",
"is": "is",
"it": "it",
"iu": "iu",
"ja": "ja",
"jv": "jv",
"ka": "ka",
"ki": "ki",
"kk": "kk",
"kl": "kl",
"km": "km",
"kn": "kn",
"ko": "ko",
"ks": "ks",
"ku": "ku",
"kw": "kw",
"ky": "ky",
"la": "la",
"lb": "lb",
"lg": "lg",
"ln": "ln",
"lo": "lo",
"lt": "lt",
"lu": "lu",
"lv": "lv",
"mg": "mg",
"mi": "mi",
"mk": "mk",
"ml": "ml",
"mn": "mn",
"mr": "mr",
"ms": "ms",
"mt": "mt",
"my": "my",
"nb": "nb",
"nd": "nd",
"ne": "ne",
"nl": "nl",
"nn": "nn",
"no": "no",
"nr": "nr",
"nv": "nv",
"ny": "ny",
"oc": "oc",
"om": "om",
"or": "or",
"os": "os",
"pa": "pa",
"pl": "pl",
"ps": "ps",
"pt": "pt",
"qu": "qu",
"rm": "rm",
"rn": "rn",
"ro": "ro",
"ru": "ru",
"rw": "rw",
"sa": "sa",
"sc": "sc",
"sd": "sd",
"se": "se",
"sg": "sg",
"si": "si",
"sk": "sk",
"sl": "sl",
"sn": "sn",
"so": "so",
"sq": "sq",
"sr": "sr",
"ss": "ss",
"st": "st",
"su": "su",
"sv": "sv",
"sw": "sw",
"ta": "ta",
"te": "te",
"tg": "tg",
"th": "th",
"ti": "ti",
"tk": "tk",
"tn": "tn",
"to": "to",
"tr": "tr",
"ts": "ts",
"tt": "tt",
"ug": "ug",
"uk": "uk",
"ur": "ur",
"uz": "uz",
"ve": "ve",
"vi": "vi",
"vo": "vo",
"wa": "wa",
"wo": "wo",
"xh": "xh",
"yi": "yi",
"yo": "yo",
"za": "za",
"zh": "zh",
"zh_Hans": "zh-cn",
"zh_Hant": "zh-tw",
"zu": "zu"
},
"regions": {}
},
"z-library": { "z-library": {
"all_locale": "", "all_locale": "",
"custom": { "custom": {
+7 -6
View File
@@ -8,8 +8,8 @@
There is a command line for developer purposes and for deeper analysis. Here is There is a command line for developer purposes and for deeper analysis. Here is
an example in which the command line is called in the development environment:: an example in which the command line is called in the development environment::
$ ./manage pyenv.cmd bash --norc --noprofile $ ./manage dev.env
(py3) python -m searx.enginelib --help (dev.env)$ python -m searx.enginelib --help
.. hint:: .. hint::
@@ -46,6 +46,7 @@ ENGINES_CACHE: ExpireCacheSQLite = ExpireCacheSQLite.build_cache(
name="ENGINES_CACHE", name="ENGINES_CACHE",
MAXHOLD_TIME=60 * 60 * 24 * 7, # 7 days MAXHOLD_TIME=60 * 60 * 24 * 7, # 7 days
MAINTENANCE_PERIOD=60 * 60, # 2h MAINTENANCE_PERIOD=60 * 60, # 2h
MAX_VALUE_LEN=1024 * 1024 * 1024, # 1MB
) )
) )
"""Global :py:obj:`searx.cache.ExpireCacheSQLite` instance where the cached """Global :py:obj:`searx.cache.ExpireCacheSQLite` instance where the cached
@@ -71,9 +72,9 @@ def state():
@app.command() @app.command()
def maintenance(force: bool = True): def maintenance(force: bool = True, truncate: bool = False):
"""Carry out maintenance on cache of the engines.""" """Carry out maintenance on cache of the engines."""
ENGINES_CACHE.maintenance(force=force) ENGINES_CACHE.maintenance(force=force, truncate=truncate)
class EngineCache: class EngineCache:
@@ -111,8 +112,8 @@ class EngineCache:
For introspection of the DB, jump into developer environment and run command to For introspection of the DB, jump into developer environment and run command to
show cache state:: show cache state::
$ ./manage pyenv.cmd bash --norc --noprofile $ ./manage dev.env
(py3) python -m searx.enginelib cache state (dev.env)$ python -m searx.enginelib cache state
cache tables and key/values cache tables and key/values
=========================== ===========================
+4
View File
@@ -84,6 +84,10 @@ def request(query, params):
def response(resp): def response(resp):
# sometimes 360search returns empty response when called from non-chinese ips
if not resp.text or not resp.text.strip():
return []
dom = html.fromstring(resp.text) dom = html.fromstring(resp.text)
results = [] results = []
-75
View File
@@ -1,75 +0,0 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Ask.com"""
from urllib.parse import urlencode
import dateutil
from lxml import html
from searx import utils
# Metadata
about = {
"website": "https://www.ask.com/",
"wikidata_id": 'Q847564',
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
}
# Engine Configuration
categories = ['general']
paging = True
max_page = 5
"""Ask.com has at max 5 pages."""
# Base URL
base_url = "https://www.ask.com/web"
def request(query, params):
query_params = {
"q": query,
"page": params["pageno"],
}
params["url"] = f"{base_url}?{urlencode(query_params)}"
return params
def response(resp):
start_tag = 'window.MESON.initialState = {'
end_tag = '}};'
dom = html.fromstring(resp.text)
script = utils.eval_xpath_getindex(dom, '//script', 0, default=None).text
pos = script.index(start_tag) + len(start_tag) - 1
script = script[pos:]
pos = script.index(end_tag) + len(end_tag) - 1
script = script[:pos]
json_resp = utils.js_obj_str_to_python(script)
results = []
for item in json_resp['search']['webResults']['results']:
pubdate_original = item.get('pubdate_original')
if pubdate_original:
pubdate_original = dateutil.parser.parse(pubdate_original)
metadata = [item.get(field) for field in ['category_l1', 'catsy'] if item.get(field)]
results.append(
{
"url": item['url'].split('&ueid')[0],
"title": item['title'],
"content": item['abstract'],
"publishedDate": pubdate_original,
# "thumbnail": item.get('image_url') or None, # these are not thumbs / to large
"metadata": ' | '.join(metadata),
}
)
return results
+85
View File
@@ -0,0 +1,85 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=invalid-name
"""Cara_ is a social media and portfolio-sharing platform for artists and art
enthusiasts.
With the widespread use of generative AI, Cara_ decided to build a place that
filters out gen AI images so that people searching for authentic creatives and
images can do so easily.
.. _Cara: https://cara.app/about
"""
from urllib.parse import urlencode
import typing as t
from searx.result_types import EngineResults
if t.TYPE_CHECKING:
from searx.extended_types import SXNG_Response
from searx.search.processors import OnlineParams
about = {
"website": "https://cara.app",
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": "JSON",
}
base_url = "https://cara.app"
images_url = "https://images.cara.app"
categories = ["images"]
paging = True
results_per_page = 24
# if using HTTP2, we get blocked immediately
enable_http2 = False
def request(query: str, params: "OnlineParams") -> None:
args = {
"q": query,
"sortBy": "Top",
"take": results_per_page,
"skip": (params["pageno"] - 1) * results_per_page,
}
params["url"] = f"{base_url}/api/search/portfolio-posts?{urlencode(args)}"
def response(resp: "SXNG_Response"):
res = EngineResults()
json_data: list[dict[str, t.Any]] = resp.json()
for result in json_data:
thumbnail, img = None, None
i: dict[str, str]
for i in result["images"]:
if thumbnail is None or i["isCoverImg"]:
thumbnail = i
if img is None or not i["isCoverImg"]:
img = i
if not thumbnail or not img:
continue
res.add(
res.types.LegacyResult(
{
"template": "images.html",
"url": f"{base_url}/post/{result['id']}",
"thumbnail_src": f"{images_url}/{thumbnail['src']}?height=256",
"img_src": f"{images_url}/{img['src']}",
"title": result["title"],
"content": result["content"],
"author": result["name"],
}
)
)
return res
+19 -1
View File
@@ -278,10 +278,28 @@ def get_google_info(params: "OnlineParams", eng_traits: EngineTraits) -> dict[st
return ret_val return ret_val
def detect_google_sorry(resp): def detect_google_sorry(resp: "SXNG_Response"):
"""Detect Google's bot-protection responses (CAPTCHA / sorry pages).
Google may block requests in several ways:
1. Redirect to sorry.google.com (standard CAPTCHA).
2. HTTP 302 redirect to ``/sorry/index?...`` on the same host -- when the
HTTP client doesn't follow the redirect, the response body is a short
HTML stub with a link to the sorry page.
3. Short HTML response (<2000 bytes) containing "/sorry/" -- a meta-refresh
or JS redirect variant.
"""
if resp.url.host == "sorry.google.com" or resp.url.path.startswith("/sorry"): if resp.url.host == "sorry.google.com" or resp.url.path.startswith("/sorry"):
raise SearxEngineCaptchaException() raise SearxEngineCaptchaException()
if resp.status_code == 302:
raise SearxEngineCaptchaException()
if len(resp.text) < 2000 and "/sorry/" in resp.text:
raise SearxEngineCaptchaException()
def request(query: str, params: "OnlineParams") -> None: def request(query: str, params: "OnlineParams") -> None:
"""Google search request""" """Google search request"""
+188 -159
View File
@@ -23,9 +23,11 @@ The google news API ignores some parameters from the common :ref:`google API`:
.. _num: https://developers.google.com/custom-search/docs/xml_results#numsp .. _num: https://developers.google.com/custom-search/docs/xml_results#numsp
.. _save: https://developers.google.com/custom-search/docs/xml_results#safesp .. _save: https://developers.google.com/custom-search/docs/xml_results#safesp
""" """
import typing as t
from urllib.parse import urlencode import json
import base64 import base64
from urllib.parse import urlencode
from lxml import html from lxml import html
import babel import babel
@@ -44,18 +46,24 @@ from searx.engines.google import (
) )
from searx.enginelib.traits import EngineTraits from searx.enginelib.traits import EngineTraits
from searx.result_types import EngineResults
if t.TYPE_CHECKING:
from searx.extended_types import SXNG_Response
from searx.search.processors import OnlineParams
# about # about
about = { about = {
"website": 'https://news.google.com', "website": "https://news.google.com",
"wikidata_id": 'Q12020', "wikidata_id": "Q12020",
"official_api_documentation": 'https://developers.google.com/custom-search', "official_api_documentation": "https://developers.google.com/custom-search",
"use_official_api": False, "use_official_api": False,
"require_api_key": False, "require_api_key": False,
"results": 'HTML', "results": "HTML",
} }
# engine dependent config # engine dependent config
categories = ['news'] categories = ["news"]
paging = False paging = False
time_range_support = False time_range_support = False
@@ -64,231 +72,252 @@ time_range_support = False
# #
# safesearch : results are identical for safesearch=0 and safesearch=2 # safesearch : results are identical for safesearch=0 and safesearch=2
safesearch = True safesearch = True
base_url: str = "https://news.google.com"
def request(query, params): def request(query: str, params: "OnlineParams") -> None:
"""Google-News search request""" """Google-News search request"""
sxng_locale = params.get('searxng_locale', 'en-US') sxng_locale = params.get("searxng_locale", "en-US")
ceid = locales.get_engine_locale(sxng_locale, traits.custom['ceid'], default='US:en') ceid: str = locales.get_engine_locale(
sxng_locale, traits.custom["ceid"], default="US:en"
) # pyright: ignore[reportAssignmentType]
google_info = get_google_info(params, traits) google_info = get_google_info(params, traits)
google_info['subdomain'] = 'news.google.com' # google news has only one domain google_info["subdomain"] = "news.google.com" # google news has only one domain
ceid_region, ceid_lang = ceid.split(':') ceid_region, ceid_lang = ceid.split(":")
ceid_lang, ceid_suffix = ( ceid_lang, ceid_suffix = (
ceid_lang.split('-') ceid_lang.split(":")
+ [ + [
None, "",
] ]
)[:2] )[:2]
google_info['params']['hl'] = ceid_lang google_info["params"]["hl"] = ceid_lang
if ceid_suffix and ceid_suffix not in ['Hans', 'Hant']: if ceid_suffix and ceid_suffix not in ["Hans", "Hant"]:
if ceid_region.lower() == ceid_lang: if ceid_region.lower() == ceid_lang:
google_info['params']['hl'] = ceid_lang + '-' + ceid_region google_info["params"]["hl"] = ceid_lang + "-" + ceid_region
else: else:
google_info['params']['hl'] = ceid_lang + '-' + ceid_suffix google_info["params"]["hl"] = ceid_lang + "-" + ceid_suffix
elif ceid_region.lower() != ceid_lang: elif ceid_region.lower() != ceid_lang:
if ceid_region in ['AT', 'BE', 'CH', 'IL', 'SA', 'IN', 'BD', 'PT']: if ceid_region in ["AT", "BE", "CH", "IL", "SA", "IN", "BD", "PT"]:
google_info['params']['hl'] = ceid_lang google_info["params"]["hl"] = ceid_lang
else: else:
google_info['params']['hl'] = ceid_lang + '-' + ceid_region google_info["params"]["hl"] = ceid_lang + "-" + ceid_region
google_info['params']['lr'] = 'lang_' + ceid_lang.split('-')[0] google_info["params"]["lr"] = "lang_" + ceid_lang.split("-")[0]
google_info['params']['gl'] = ceid_region google_info["params"]["gl"] = ceid_region
query_url = ( query_url = (
'https://' "https://"
+ google_info['subdomain'] + google_info["subdomain"]
+ "/search?" + "/search?"
+ urlencode( + urlencode(
{ {"q": query, **google_info["params"]},
'q': query,
**google_info['params'],
}
) )
# ceid includes a ':' character which must not be urlencoded # ceid includes a ':' character which must not be urlencoded
+ ('&ceid=%s' % ceid) + ("&ceid=%s" % ceid)
) )
params['url'] = query_url params["url"] = query_url
params['cookies'] = google_info['cookies'] params["cookies"] = google_info["cookies"]
params['headers'].update(google_info['headers']) params["headers"].update(google_info["headers"])
return params
def response(resp): def response(resp: "SXNG_Response") -> EngineResults:
"""Get response from google's search request""" """Get response from google's search request"""
results = []
res = EngineResults()
detect_google_sorry(resp) detect_google_sorry(resp)
# convert the text to dom # convert the text to dom
dom = html.fromstring(resp.text) dom = html.fromstring(resp.text)
for result in eval_xpath_list(dom, '//div[@class="xrnccd"]'): for result in eval_xpath_list(dom, "//div[@jslog and @data-n-tid and @jsdata]"):
# The first <a> tag in the <article> contains the link to the article url: str = eval_xpath_getindex(result, "./a[@target='_blank']/@href", 0, default=0)
# The href attribute of the <a> tag is a google internal link, we have if not url:
# to decode continue
if url.startswith("./"):
url = base_url + url[1:]
href = eval_xpath_getindex(result, './article/a/@href', 0) # The real URL is often encoded in the "jslog" attribute
href = href.split('?')[0] jslog: str | None = eval_xpath_getindex(result, "./a[@target='_blank']/@jslog", 0, default=None)
href = href.split('/')[-1]
href = base64.urlsafe_b64decode(href + '====')
href = href[href.index(b'http') :].split(b'\xd2')[0]
href = href.decode()
title = extract_text(eval_xpath(result, './article/h3[1]')) # Try to extract the real URL from jslog
real_url: str | None = None
if jslog:
# jslog format is usually: "95014; 5:<base64>; track:click,vis". We
# want the second part (index 1) after splitting by ";"
parts: list[str] = jslog.split(";")
if len(parts) > 1:
b64_data: str = parts[1].split(":")[-1].strip()
# Pad base64 if necessary
b64_data += "=" * (-len(b64_data) % 4)
decoded_data: list[str | None] = json.loads(base64.b64decode(b64_data).decode("utf-8"))
# The URL is typically the last element in the decoded array
if (
isinstance(decoded_data, list)
and isinstance(decoded_data[-1], str)
and decoded_data[-1].startswith("http")
):
real_url = decoded_data[-1]
if real_url:
url = real_url
else:
logger.error(f"no real-url found: {url}")
continue
# The pub_date is mostly a string like 'yesterday', not a real title = extract_text(eval_xpath(result, "./h4")) or ""
# timezone date or time. Therefore we can't use publishedDate.
pub_date = extract_text(eval_xpath(result, './article//time'))
pub_origin = extract_text(eval_xpath(result, './article//a[@data-n-tid]'))
content = ' / '.join([x for x in [pub_origin, pub_date] if x]) # The pub_date is mostly a string like 'yesterday', not a real timezone
# date or time. Therefore we can't use publishedDate and place the
# *pub* sting into the content.
# The image URL is located in a preceding sibling <img> tag, e.g.: pub_date = extract_text(eval_xpath(result, ".//time"))
# "https://lh3.googleusercontent.com/DjhQh7DMszk.....z=-p-h100-w100" pub_origin = extract_text(eval_xpath(result, ".//div[contains(@class, 'vr1PYe')]"))
# These URL are long but not personalized (double checked via tor). content = " / ".join([x for x in [pub_origin, pub_date] if x])
thumbnail = extract_text(result.xpath('preceding-sibling::a/figure/img/@src')) thumbnail: str = eval_xpath_getindex(result, ".//figure/img/@src", 0, default="")
if thumbnail and thumbnail.startswith("/"):
thumbnail = base_url + thumbnail
results.append( res.add(
{ res.types.MainResult(
'url': href, url=url,
'title': title, title=title,
'content': content, content=content,
'thumbnail': thumbnail, thumbnail=thumbnail,
} )
) )
# return results return res
return results
ceid_list = [ ceid_list = [
'AE:ar', "AE:ar",
'AR:es-419', "AR:es-419",
'AT:de', "AT:de",
'AU:en', "AU:en",
'BD:bn', "BD:bn",
'BE:fr', "BE:fr",
'BE:nl', "BE:nl",
'BG:bg', "BG:bg",
'BR:pt-419', "BR:pt-419",
'BW:en', "BW:en",
'CA:en', "CA:en",
'CA:fr', "CA:fr",
'CH:de', "CH:de",
'CH:fr', "CH:fr",
'CL:es-419', "CL:es-419",
'CN:zh-Hans', "CN:zh-Hans",
'CO:es-419', "CO:es-419",
'CU:es-419', "CU:es-419",
'CZ:cs', "CZ:cs",
'DE:de', "DE:de",
'EG:ar', "EE:et",
'ES:es', "EG:ar",
'ET:en', "ES:ca",
'FR:fr', "ES:es",
'GB:en', "ET:en",
'GH:en', "FI:fi",
'GR:el', "FR:fr",
'HK:zh-Hant', "GB:en",
'HU:hu', "GH:en",
'ID:en', "GR:el",
'ID:id', "HK:zh-Hant",
'IE:en', "HU:hu",
'IL:en', "ID:en",
'IL:he', "ID:id",
'IN:bn', "IE:en",
'IN:en', "IL:en",
'IN:hi', "IL:he",
'IN:ml', "IN:bn",
'IN:mr', "IN:en",
'IN:ta', "IN:gu",
'IN:te', "IN:hi",
'IT:it', "IN:ml",
'JP:ja', "IN:mr",
'KE:en', "IN:pa",
'KR:ko', "IN:ta",
'LB:ar', "IN:te",
'LT:lt', "IT:it",
'LV:en', "JP:ja",
'LV:lv', "KE:en",
'MA:fr', "KR:ko",
'MX:es-419', "LB:ar",
'MY:en', "LT:lt",
'NA:en', "LV:en",
'NG:en', "LV:lv",
'NL:nl', "MA:fr",
'NO:no', "MY:en",
'NZ:en', "MY:ms",
'PE:es-419', "NA:en",
'PH:en', "NG:en",
'PK:en', "NL:nl",
'PL:pl', "NO:no",
'PT:pt-150', "NZ:en",
'RO:ro', "PH:en",
'RS:sr', "PK:en",
'RU:ru', "PL:pl",
'SA:ar', "RO:ro",
'SE:sv', "RS:sr",
'SG:en', "RU:ru",
'SI:sl', "SA:ar",
'SK:sk', "SE:sv",
'SN:fr', "SG:en",
'TH:th', "SI:sl",
'TR:tr', "SK:sk",
'TW:zh-Hant', "SN:fr",
'TZ:en', "TH:th",
'UA:ru', "TR:tr",
'UA:uk', "TZ:en",
'UG:en', "UA:ru",
'US:en', "UA:uk",
'US:es-419', "UG:en",
'VE:es-419', "US:en",
'VN:vi', "VN:vi",
'ZA:en', "ZA:en",
'ZW:en', "ZW:en",
] ]
"""List of region/language combinations supported by Google News. Values of the """List of region/language combinations supported by Google News. Values of the
``ceid`` argument of the Google News REST API.""" ``ceid`` argument of the Google News REST API."""
_skip_values = [ _skip_values = [
'ET:en', # english (ethiopia) "ET:en", # english (ethiopia)
'ID:en', # english (indonesia) "ID:en", # english (indonesia)
'LV:en', # english (latvia) "LV:en", # english (latvia)
] ]
_ceid_locale_map = {'NO:no': 'nb-NO'} _ceid_locale_map = {"NO:no": "nb-NO"}
def fetch_traits(engine_traits: EngineTraits): def fetch_traits(engine_traits: EngineTraits):
_fetch_traits(engine_traits, add_domains=False) _fetch_traits(engine_traits, add_domains=False)
engine_traits.custom['ceid'] = {} engine_traits.custom["ceid"] = {}
for ceid in ceid_list: for ceid in ceid_list:
if ceid in _skip_values: if ceid in _skip_values:
continue continue
region, lang = ceid.split(':') region, lang = ceid.split(":")
x = lang.split('-') x = lang.split("-")
if len(x) > 1: if len(x) > 1:
if x[1] not in ['Hant', 'Hans']: if x[1] not in ["Hant", "Hans"]:
lang = x[0] lang = x[0]
sxng_locale = _ceid_locale_map.get(ceid, lang + '-' + region) sxng_locale = _ceid_locale_map.get(ceid, lang + "-" + region)
try: try:
locale = babel.Locale.parse(sxng_locale, sep='-') locale = babel.Locale.parse(sxng_locale, sep="-")
except babel.UnknownLocaleError: except babel.UnknownLocaleError:
print("ERROR: %s -> %s is unknown by babel" % (ceid, sxng_locale)) print("ERROR: %s -> %s is unknown by babel" % (ceid, sxng_locale))
continue continue
engine_traits.custom['ceid'][locales.region_tag(locale)] = ceid engine_traits.custom["ceid"][locales.region_tag(locale)] = ceid
+2 -1
View File
@@ -39,11 +39,12 @@ def response(resp):
for result in json_results: for result in json_results:
title_parts = [title['value'] for title in result['title']] title_parts = [title['value'] for title in result['title']]
extract_parts = [extract['value'] for extract in result.get('extract', [])]
results.append( results.append(
{ {
'url': result['url'], 'url': result['url'],
'title': ''.join(title_parts), 'title': ''.join(title_parts),
'content': result['extract'][0]['value'], 'content': ''.join(extract_parts),
} }
) )
+4 -1
View File
@@ -345,7 +345,10 @@ def _get_news_result(result):
publishedDate = None publishedDate = None
if result.get("date"): if result.get("date"):
publishedDate = datetime.fromtimestamp(result["date"] / 1000) try:
publishedDate = datetime.fromtimestamp(int(result["date"]) / 1000)
except (TypeError, ValueError):
pass
thumbnailUrl = None thumbnailUrl = None
if result.get("thumbnailUrl"): if result.get("thumbnailUrl"):
+552 -498
View File
File diff suppressed because it is too large Load Diff
+12 -11
View File
@@ -87,7 +87,6 @@ def request(query, params):
def response(resp): def response(resp):
if search_type == 'web': if search_type == 'web':
catch_bad_response(resp) catch_bad_response(resp)
dom = html.fromstring(resp.text) dom = html.fromstring(resp.text)
@@ -106,7 +105,6 @@ def response(resp):
return results return results
if search_type == 'images': if search_type == 'images':
catch_bad_response(resp) catch_bad_response(resp)
html_data = html.fromstring(resp.text) html_data = html.fromstring(resp.text)
@@ -127,22 +125,25 @@ def response(resp):
for _, item_data in json_resp['initialState']['serpList']['items']['entities'].items(): for _, item_data in json_resp['initialState']['serpList']['items']['entities'].items():
title = item_data['snippet']['title'] title = item_data['snippet']['title']
source = item_data['snippet']['url'] source = item_data['snippet']['url']
thumb = item_data['image']
fullsize_image = item_data['viewerData']['dups'][0]['url'] image_source = item_data["viewerData"]["thumb"]
height = item_data['viewerData']['dups'][0]['h'] for i in item_data['viewerData']['dups'] + item_data['viewerData']['preview']:
width = item_data['viewerData']['dups'][0]['w'] if i["h"] > image_source["h"]:
filesize = item_data['viewerData']['dups'][0]['fileSizeInBytes'] image_source = i
humanized_filesize = humanize_bytes(filesize)
humanized_filesize = None
if image_source.get("fileSizeInBytes"):
humanized_filesize = humanize_bytes(image_source["fileSizeInBytes"])
results.append( results.append(
{ {
'title': title, 'title': title,
'url': source, 'url': source,
'img_src': fullsize_image, 'img_src': image_source["url"],
'filesize': humanized_filesize, 'filesize': humanized_filesize,
'thumbnail_src': thumb, 'thumbnail_src': item_data["image"],
'template': 'images.html', 'template': 'images.html',
'resolution': f'{width} x {height}', 'resolution': f'{image_source["w"]} x {image_source["h"]}',
} }
) )
+103 -53
View File
@@ -1,9 +1,19 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Yep (general, images, news)""" """Yep (general, images, news)"""
from datetime import datetime import re
import typing as t
from urllib.parse import urlencode from urllib.parse import urlencode
from searx.utils import html_to_text
from searx.result_types import EngineResults
from searx.utils import html_to_text, eval_xpath_getindex, extract_text
if t.TYPE_CHECKING:
from searx.enginelib.traits import EngineTraits
from searx.extended_types import SXNG_Response
from searx.search.processors import OnlineParams
about = { about = {
'website': 'https://yep.com/', 'website': 'https://yep.com/',
@@ -14,69 +24,109 @@ about = {
} }
base_url = "https://api.yep.com" base_url = "https://api.yep.com"
search_type = "web" # 'web', 'images', 'news'
safesearch = True safesearch = True
safesearch_map = {0: 'off', 1: 'moderate', 2: 'strict'} safesearch_map = {0: 'off', 1: 'moderate', 2: 'strict'}
enable_http2 = False enable_http2 = False
results_per_page = 20
_IMPORT_RE = re.compile(r"import\"(.*?)\";")
_LANGUAGE_RE = re.compile(r"\{english:\".*?\",code_string:\"(.*?)\",code:\".*?\"\}")
def request(query: str, params: 'OnlineParams') -> None:
args = {'query': query, 'safeSearch': safesearch_map[params['safesearch']], 'limit': results_per_page}
engine_language: str = traits.get_language(params["searxng_locale"])
if engine_language:
args["hl"] = engine_language
def request(query, params):
args = {
'client': 'web',
'no_correct': 'false',
'q': query,
'safeSearch': safesearch_map[params['safesearch']],
'type': search_type,
}
params['url'] = f"{base_url}/fs/2/search?{urlencode(args)}" params['url'] = f"{base_url}/fs/2/search?{urlencode(args)}"
params['headers']['Referer'] = 'https://yep.com/' params['headers']['Referer'] = 'https://yep.com/'
params['headers']['Origin'] = 'https://yep.com' params['headers']['Origin'] = 'https://yep.com'
return params
def _web_result(result): def response(resp: 'SXNG_Response') -> EngineResults:
return { res = EngineResults()
'url': result['url'],
'title': result['title'],
'content': html_to_text(result['snippet']),
}
def _images_result(result):
return {
'template': 'images.html',
'url': result['host_page'],
'title': result.get('title', ''),
'content': '',
'img_src': result['image_id'],
'thumbnail_src': result['src'],
}
def _news_result(result):
return {
'url': result['url'],
'title': result['title'],
'content': html_to_text(result['snippet']),
'publishedDate': datetime.strptime(result['first_seen'][:19], '%Y-%m-%dT%H:%M:%S'),
}
def response(resp):
results = []
for result in resp.json()[1]['results']: for result in resp.json()[1]['results']:
if search_type == "web": res.add(
if result['type'] != 'Organic': res.types.MainResult(
continue url=result['url'],
results.append(_web_result(result)) title=result['title'],
elif search_type == "images": content=html_to_text(result['snippet']),
results.append(_images_result(result)) )
elif search_type == "news": )
results.append(_news_result(result))
else:
raise ValueError(f"Unsupported yep search type: {search_type}")
return results return res
def fetch_traits(engine_traits: 'EngineTraits'):
"""Fetch :ref:`languages <yep languages>` and :ref:`regions <yep
regions>` from Yep.
The language options are very well hidden on Yep. To get it, we have to do the following:
- Load the yep.com mainpage and extract the URL of the JavaScript app
- Load the JavaScript source code and extract the URL of all imported modules from it
- Load the imported modules to search for the right one that contains the languages
"""
# pylint: disable=import-outside-toplevel, too-many-branches
from lxml import html
import babel
from searx.locales import language_tag
from searx.network import get # see https://github.com/searxng/searxng/issues/762
from searx.utils import gen_useragent
web_base_url = "https://yep.com"
headers = {
"User-Agent": gen_useragent(),
"Referer": f"{web_base_url}/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
}
resp = get(web_base_url, headers=headers, timeout=5)
if not resp.ok:
raise RuntimeError("Response from Yep languages is not OK.")
doc = html.fromstring(resp.text)
url = eval_xpath_getindex(doc, "//script[contains(@src, 'PageApp')]/@src", index=0)
resp = get("https:" + extract_text(url), headers=headers, timeout=5)
if not resp.ok:
raise RuntimeError("Response from Yep languages is not OK.")
language_codes = []
for script_path in _IMPORT_RE.findall(resp.text):
resp = get(f"{web_base_url}{script_path}", headers=headers, timeout=5)
if not resp.ok:
raise RuntimeError("Response from Yep languages is not OK.")
for match in _LANGUAGE_RE.findall(resp.text):
language_codes.append(match)
if language_codes:
break
for language_code in language_codes:
try:
sxng_tag = language_tag(babel.Locale.parse(language_code, sep="-"))
except babel.UnknownLocaleError:
# silently ignore unknown languages
continue
# print("%-20s: %s <-- %s" % (extract_text(option), country_tag, sxng_tag))
conflict = engine_traits.languages.get(sxng_tag)
if conflict:
if conflict != sxng_tag:
print("CONFLICT: babel %s --> %s, %s" % (sxng_tag, conflict, language_code))
continue
engine_traits.languages[sxng_tag] = language_code
+3 -3
View File
@@ -16,12 +16,12 @@ IMDB_PREFIX_TO_URL_ID = {
HTTP_WIKIMEDIA_IMAGE = 'http://commons.wikimedia.org/wiki/Special:FilePath/' HTTP_WIKIMEDIA_IMAGE = 'http://commons.wikimedia.org/wiki/Special:FilePath/'
def get_imdb_url_id(imdb_item_id): def get_imdb_url_id(imdb_item_id: str):
id_prefix = imdb_item_id[:2] id_prefix = imdb_item_id[:2]
return IMDB_PREFIX_TO_URL_ID.get(id_prefix) return IMDB_PREFIX_TO_URL_ID.get(id_prefix)
def get_wikimedia_image_id(url): def get_wikimedia_image_id(url: str):
if url.startswith(HTTP_WIKIMEDIA_IMAGE): if url.startswith(HTTP_WIKIMEDIA_IMAGE):
return url[len(HTTP_WIKIMEDIA_IMAGE) :] return url[len(HTTP_WIKIMEDIA_IMAGE) :]
if url.startswith('File:'): if url.startswith('File:'):
@@ -29,7 +29,7 @@ def get_wikimedia_image_id(url):
return url return url
def get_external_url(url_id, item_id, alternative="default"): def get_external_url(url_id: str, item_id: str | None, alternative: str = "default") -> str | None:
"""Return an external URL or None if url_id is not found. """Return an external URL or None if url_id is not found.
url_id can take value from data/external_urls.json url_id can take value from data/external_urls.json
+12 -23
View File
@@ -302,7 +302,7 @@ engines:
- name: 360search - name: 360search
engine: 360search engine: 360search
shortcut: 360so shortcut: 360so
timeout: 10.0 timeout: 20.0
disabled: true disabled: true
- name: 360search videos - name: 360search videos
@@ -469,11 +469,6 @@ engines:
engine: arxiv engine: arxiv
shortcut: arx shortcut: arx
- name: ask
engine: ask
shortcut: ask
disabled: true
- name: azure - name: azure
engine: azure engine: azure
shortcut: az shortcut: az
@@ -600,6 +595,11 @@ engines:
shortcut: cos shortcut: cos
disabled: true disabled: true
- name: cara
engine: cara
shortcut: ca
disabled: true
- name: chefkoch - name: chefkoch
engine: chefkoch engine: chefkoch
shortcut: chef shortcut: chef
@@ -688,22 +688,6 @@ engines:
engine: yep engine: yep
shortcut: yep shortcut: yep
categories: general categories: general
search_type: web
timeout: 15
disabled: true
- name: yep images
engine: yep
shortcut: yepi
categories: images
search_type: images
disabled: true
- name: yep news
engine: yep
shortcut: yepn
categories: news
search_type: news
disabled: true disabled: true
- name: currency - name: currency
@@ -1219,6 +1203,7 @@ engines:
categories: [general, web] categories: [general, web]
search_type: web search_type: web
shortcut: ka shortcut: ka
inactive: true
- name: karmasearch images - name: karmasearch images
engine: karmasearch engine: karmasearch
@@ -1226,18 +1211,21 @@ engines:
search_type: images search_type: images
shortcut: kai shortcut: kai
paging: false paging: false
inactive: true
- name: karmasearch videos - name: karmasearch videos
engine: karmasearch engine: karmasearch
categories: [general, web] categories: [videos, web]
search_type: videos search_type: videos
shortcut: kav shortcut: kav
inactive: true
- name: karmasearch news - name: karmasearch news
engine: karmasearch engine: karmasearch
categories: [news, web] categories: [news, web]
search_type: news search_type: news
shortcut: kan shortcut: kan
inactive: true
- name: kickass - name: kickass
engine: kickass engine: kickass
@@ -2165,6 +2153,7 @@ engines:
- name: yahoo news - name: yahoo news
engine: yahoo_news engine: yahoo_news
shortcut: yhn shortcut: yhn
inactive: true
- name: youtube - name: youtube
shortcut: yt shortcut: yt
@@ -1 +1 @@
{"version":3,"file":"BnP4vIuG.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/search.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen } from \"../toolkit.ts\";\nimport { getElement } from \"../util/getElement.ts\";\n\nconst searchForm: HTMLFormElement = getElement<HTMLFormElement>(\"search\");\nconst searchInput: HTMLInputElement = getElement<HTMLInputElement>(\"q\");\nconst searchReset: HTMLButtonElement = getElement<HTMLButtonElement>(\"clear_search\");\n\nconst isMobile: boolean = window.matchMedia(\"(max-width: 50em)\").matches;\nconst isResultsPage: boolean = document.querySelector(\"main\")?.id === \"main_results\";\n\nconst categoryButtons: HTMLButtonElement[] = Array.from(\n document.querySelectorAll<HTMLButtonElement>(\"#categories_container button.category\")\n);\n\nif (searchInput.value.length === 0) {\n searchReset.classList.add(\"empty\");\n}\n\n// focus search input on large screens\nif (!(isMobile || isResultsPage)) {\n searchInput.focus();\n}\n\n// On mobile, move cursor to the end of the input on focus\nif (isMobile) {\n listen(\"focus\", searchInput, () => {\n // Defer cursor move until the next frame to prevent a visual jump\n requestAnimationFrame(() => {\n const end = searchInput.value.length;\n searchInput.setSelectionRange(end, end);\n searchInput.scrollLeft = searchInput.scrollWidth;\n });\n });\n}\n\nlisten(\"input\", searchInput, () => {\n searchReset.classList.toggle(\"empty\", searchInput.value.length === 0);\n});\n\nlisten(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\n searchReset.classList.add(\"empty\");\n});\n\nfor (const button of categoryButtons) {\n listen(\"click\", button, (event: MouseEvent) => {\n if (event.shiftKey) {\n event.preventDefault();\n button.classList.toggle(\"selected\");\n return;\n }\n\n // deselect all other categories\n for (const categoryButton of categoryButtons) {\n categoryButton.classList.toggle(\"selected\", categoryButton === button);\n }\n });\n}\n\nif (document.querySelector(\"div.search_filters\")) {\n const safesearchElement = document.getElementById(\"safesearch\");\n if (safesearchElement) {\n listen(\"change\", safesearchElement, () => searchForm.submit());\n }\n\n const timeRangeElement = document.getElementById(\"time_range\");\n if (timeRangeElement) {\n listen(\"change\", timeRangeElement, () => searchForm.submit());\n }\n\n const languageElement = document.getElementById(\"language\");\n if (languageElement) {\n listen(\"change\", languageElement, () => searchForm.submit());\n }\n}\n\n// override searchForm submit event\nlisten(\"submit\", searchForm, (event: Event) => {\n event.preventDefault();\n\n if (categoryButtons.length > 0) {\n const searchCategories = getElement<HTMLInputElement>(\"selected-categories\");\n searchCategories.value = categoryButtons\n .filter((button) => button.classList.contains(\"selected\"))\n .map((button) => button.name.replace(\"category_\", \"\"))\n .join(\",\");\n }\n\n searchForm.submit();\n});\n"],"mappings":"yEAKA,IAAM,EAA8B,EAA4B,SAAS,CACnE,EAAgC,EAA6B,IAAI,CACjE,EAAiC,EAA8B,eAAe,CAE9E,EAAoB,OAAO,WAAW,oBAAoB,CAAC,QAC3D,EAAyB,SAAS,cAAc,OAAO,EAAE,KAAO,eAEhE,EAAuC,MAAM,KACjD,SAAS,iBAAoC,wCAAwC,CACtF,CAEG,EAAY,MAAM,SAAW,GAC/B,EAAY,UAAU,IAAI,QAAQ,CAI9B,GAAY,GAChB,EAAY,OAAO,CAIjB,GACF,EAAO,QAAS,MAAmB,CAEjC,0BAA4B,CAC1B,IAAM,EAAM,EAAY,MAAM,OAC9B,EAAY,kBAAkB,EAAK,EAAI,CACvC,EAAY,WAAa,EAAY,aACrC,EACF,CAGJ,EAAO,QAAS,MAAmB,CACjC,EAAY,UAAU,OAAO,QAAS,EAAY,MAAM,SAAW,EAAE,EACrE,CAEF,EAAO,QAAS,EAAc,GAAsB,CAClD,EAAM,gBAAgB,CACtB,EAAY,MAAQ,GACpB,EAAY,OAAO,CACnB,EAAY,UAAU,IAAI,QAAQ,EAClC,CAEF,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,EAAS,GAAsB,CAC7C,GAAI,EAAM,SAAU,CAClB,EAAM,gBAAgB,CACtB,EAAO,UAAU,OAAO,WAAW,CACnC,OAIF,IAAK,IAAM,KAAkB,EAC3B,EAAe,UAAU,OAAO,WAAY,IAAmB,EAAO,EAExE,CAGJ,GAAI,SAAS,cAAc,qBAAqB,CAAE,CAChD,IAAM,EAAoB,SAAS,eAAe,aAAa,CAC3D,GACF,EAAO,SAAU,MAAyB,EAAW,QAAQ,CAAC,CAGhE,IAAM,EAAmB,SAAS,eAAe,aAAa,CAC1D,GACF,EAAO,SAAU,MAAwB,EAAW,QAAQ,CAAC,CAG/D,IAAM,EAAkB,SAAS,eAAe,WAAW,CACvD,GACF,EAAO,SAAU,MAAuB,EAAW,QAAQ,CAAC,CAKhE,EAAO,SAAU,EAAa,GAAiB,CAG7C,GAFA,EAAM,gBAAgB,CAElB,EAAgB,OAAS,EAAG,CAC9B,IAAM,EAAmB,EAA6B,sBAAsB,CAC5E,EAAiB,MAAQ,EACtB,OAAQ,GAAW,EAAO,UAAU,SAAS,WAAW,CAAC,CACzD,IAAK,GAAW,EAAO,KAAK,QAAQ,YAAa,GAAG,CAAC,CACrD,KAAK,IAAI,CAGd,EAAW,QAAQ,EACnB"} {"version":3,"file":"BnP4vIuG.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/search.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen } from \"../toolkit.ts\";\nimport { getElement } from \"../util/getElement.ts\";\n\nconst searchForm: HTMLFormElement = getElement<HTMLFormElement>(\"search\");\nconst searchInput: HTMLInputElement = getElement<HTMLInputElement>(\"q\");\nconst searchReset: HTMLButtonElement = getElement<HTMLButtonElement>(\"clear_search\");\n\nconst isMobile: boolean = window.matchMedia(\"(max-width: 50em)\").matches;\nconst isResultsPage: boolean = document.querySelector(\"main\")?.id === \"main_results\";\n\nconst categoryButtons: HTMLButtonElement[] = Array.from(\n document.querySelectorAll<HTMLButtonElement>(\"#categories_container button.category\")\n);\n\nif (searchInput.value.length === 0) {\n searchReset.classList.add(\"empty\");\n}\n\n// focus search input on large screens\nif (!(isMobile || isResultsPage)) {\n searchInput.focus();\n}\n\n// On mobile, move cursor to the end of the input on focus\nif (isMobile) {\n listen(\"focus\", searchInput, () => {\n // Defer cursor move until the next frame to prevent a visual jump\n requestAnimationFrame(() => {\n const end = searchInput.value.length;\n searchInput.setSelectionRange(end, end);\n searchInput.scrollLeft = searchInput.scrollWidth;\n });\n });\n}\n\nlisten(\"input\", searchInput, () => {\n searchReset.classList.toggle(\"empty\", searchInput.value.length === 0);\n});\n\nlisten(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\n searchReset.classList.add(\"empty\");\n});\n\nfor (const button of categoryButtons) {\n listen(\"click\", button, (event: MouseEvent) => {\n if (event.shiftKey) {\n event.preventDefault();\n button.classList.toggle(\"selected\");\n return;\n }\n\n // deselect all other categories\n for (const categoryButton of categoryButtons) {\n categoryButton.classList.toggle(\"selected\", categoryButton === button);\n }\n });\n}\n\nif (document.querySelector(\"div.search_filters\")) {\n const safesearchElement = document.getElementById(\"safesearch\");\n if (safesearchElement) {\n listen(\"change\", safesearchElement, () => searchForm.submit());\n }\n\n const timeRangeElement = document.getElementById(\"time_range\");\n if (timeRangeElement) {\n listen(\"change\", timeRangeElement, () => searchForm.submit());\n }\n\n const languageElement = document.getElementById(\"language\");\n if (languageElement) {\n listen(\"change\", languageElement, () => searchForm.submit());\n }\n}\n\n// override searchForm submit event\nlisten(\"submit\", searchForm, (event: Event) => {\n event.preventDefault();\n\n if (categoryButtons.length > 0) {\n const searchCategories = getElement<HTMLInputElement>(\"selected-categories\");\n searchCategories.value = categoryButtons\n .filter((button) => button.classList.contains(\"selected\"))\n .map((button) => button.name.replace(\"category_\", \"\"))\n .join(\",\");\n }\n\n searchForm.submit();\n});\n"],"mappings":"yEAKA,IAAM,EAA8B,EAA4B,QAAQ,EAClE,EAAgC,EAA6B,GAAG,EAChE,EAAiC,EAA8B,cAAc,EAE7E,EAAoB,OAAO,WAAW,mBAAmB,EAAE,QAC3D,EAAyB,SAAS,cAAc,MAAM,GAAG,KAAO,eAEhE,EAAuC,MAAM,KACjD,SAAS,iBAAoC,uCAAuC,CACtF,EAEI,EAAY,MAAM,SAAW,GAC/B,EAAY,UAAU,IAAI,OAAO,EAI7B,GAAY,GAChB,EAAY,MAAM,EAIhB,GACF,EAAO,QAAS,MAAmB,CAEjC,0BAA4B,CAC1B,IAAM,EAAM,EAAY,MAAM,OAC9B,EAAY,kBAAkB,EAAK,CAAG,EACtC,EAAY,WAAa,EAAY,WACvC,CAAC,CACH,CAAC,EAGH,EAAO,QAAS,MAAmB,CACjC,EAAY,UAAU,OAAO,QAAS,EAAY,MAAM,SAAW,CAAC,CACtE,CAAC,EAED,EAAO,QAAS,EAAc,GAAsB,CAClD,EAAM,eAAe,EACrB,EAAY,MAAQ,GACpB,EAAY,MAAM,EAClB,EAAY,UAAU,IAAI,OAAO,CACnC,CAAC,EAED,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,EAAS,GAAsB,CAC7C,GAAI,EAAM,SAAU,CAClB,EAAM,eAAe,EACrB,EAAO,UAAU,OAAO,UAAU,EAClC,MACF,CAGA,IAAK,IAAM,KAAkB,EAC3B,EAAe,UAAU,OAAO,WAAY,IAAmB,CAAM,CAEzE,CAAC,EAGH,GAAI,SAAS,cAAc,oBAAoB,EAAG,CAChD,IAAM,EAAoB,SAAS,eAAe,YAAY,EAC1D,GACF,EAAO,SAAU,MAAyB,EAAW,OAAO,CAAC,EAG/D,IAAM,EAAmB,SAAS,eAAe,YAAY,EACzD,GACF,EAAO,SAAU,MAAwB,EAAW,OAAO,CAAC,EAG9D,IAAM,EAAkB,SAAS,eAAe,UAAU,EACtD,GACF,EAAO,SAAU,MAAuB,EAAW,OAAO,CAAC,CAE/D,CAGA,EAAO,SAAU,EAAa,GAAiB,CAG7C,GAFA,EAAM,eAAe,EAEjB,EAAgB,OAAS,EAAG,CAC9B,IAAM,EAAmB,EAA6B,qBAAqB,EAC3E,EAAiB,MAAQ,EACtB,OAAQ,GAAW,EAAO,UAAU,SAAS,UAAU,CAAC,EACxD,IAAK,GAAW,EAAO,KAAK,QAAQ,YAAa,EAAE,CAAC,EACpD,KAAK,GAAG,CACb,CAEA,EAAW,OAAO,CACpB,CAAC"}
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

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