mirror of
https://github.com/searxng/searxng.git
synced 2026-05-20 01:44:32 +02:00
Compare commits
28 Commits
330d56bba9
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| d7e8b7cd18 | |||
| f26e450778 | |||
| dce3bb69bb | |||
| de49d27846 | |||
| 16a7537bfd | |||
| afafca93f3 | |||
| 240f403d93 | |||
| 9b30ae005b | |||
| 790683bbd7 | |||
| 52b446b4ad | |||
| 6cee4b8947 | |||
| 8e5aa9d394 | |||
| cf4d7e31c4 | |||
| 471f2b205f | |||
| 09829b1ccc | |||
| df1f24fb7f | |||
| 0cba32c15f | |||
| 849e17e431 | |||
| d8ab61a9e0 | |||
| 7eb130b1a8 | |||
| ef6290c8cd | |||
| 89aa588b27 | |||
| 50626ef150 | |||
| 2f72fc4df2 | |||
| 130cea600d | |||
| ea63c19b27 | |||
| a9909c4977 | |||
| a480560371 |
@@ -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"
|
||||||
|
|||||||
Generated
+140
-151
@@ -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",
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+57
@@ -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
@@ -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;
|
|
||||||
}
|
|
||||||
Vendored
-7
@@ -1,7 +0,0 @@
|
|||||||
[theme]
|
|
||||||
inherit = pocoo
|
|
||||||
stylesheet = searxng.css
|
|
||||||
|
|
||||||
[options]
|
|
||||||
touch_icon =
|
|
||||||
globaltoc_maxdepth = 5
|
|
||||||
@@ -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`).
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
======================
|
======================
|
||||||
|
|||||||
@@ -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
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
|
|||||||
@@ -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`.
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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`_
|
|
||||||
- ..
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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": "💾",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "searx.space",
|
||||||
|
"url": "https://searx.space/",
|
||||||
|
"html": "🌐",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ----------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
How to contribute
|
How to contribute
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
Prime directives: Privacy, Hackability
|
Prime directives: Privacy, Hackability
|
||||||
======================================
|
======================================
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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 ..
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
Arch Linux
|
Arch Linux
|
||||||
==========
|
==========
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.archlinux
|
.. automodule:: searx.engines.archlinux
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Bing Engines
|
Bing Engines
|
||||||
============
|
============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. _bing web engine:
|
.. _bing web engine:
|
||||||
|
|
||||||
Bing WEB
|
Bing WEB
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Bpb
|
Bpb
|
||||||
===
|
===
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.bpb
|
.. automodule:: searx.engines.bpb
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
BT4G
|
BT4G
|
||||||
====
|
====
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.bt4g
|
.. automodule:: searx.engines.bt4g
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.. _cara engine:
|
||||||
|
|
||||||
|
===========
|
||||||
|
Cara Images
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. automodule:: searx.engines.cara
|
||||||
|
:members:
|
||||||
@@ -4,10 +4,5 @@
|
|||||||
CORE
|
CORE
|
||||||
====
|
====
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.core
|
.. automodule:: searx.engines.core
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Dailymotion
|
Dailymotion
|
||||||
===========
|
===========
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.dailymotion
|
.. automodule:: searx.engines.dailymotion
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
DuckDuckGo Engines
|
DuckDuckGo Engines
|
||||||
==================
|
==================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.duckduckgo
|
.. automodule:: searx.engines.duckduckgo
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Google Engines
|
Google Engines
|
||||||
==============
|
==============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. _google API:
|
.. _google API:
|
||||||
|
|
||||||
Google API
|
Google API
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Lemmy
|
Lemmy
|
||||||
=====
|
=====
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.lemmy
|
.. automodule:: searx.engines.lemmy
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Mastodon
|
Mastodon
|
||||||
========
|
========
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.mastodon
|
.. automodule:: searx.engines.mastodon
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Moviepilot
|
Moviepilot
|
||||||
==========
|
==========
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.moviepilot
|
.. automodule:: searx.engines.moviepilot
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Mwmbl Engine
|
Mwmbl Engine
|
||||||
============
|
============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. _mwmbl web engine:
|
.. _mwmbl web engine:
|
||||||
|
|
||||||
Mwmbl WEB
|
Mwmbl WEB
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Odysee
|
Odysee
|
||||||
======
|
======
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.odysee
|
.. automodule:: searx.engines.odysee
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Peertube Engines
|
Peertube Engines
|
||||||
================
|
================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. _peertube video engine:
|
.. _peertube video engine:
|
||||||
|
|
||||||
Peertube Video
|
Peertube Video
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Piped
|
Piped
|
||||||
=====
|
=====
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.piped
|
.. automodule:: searx.engines.piped
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Presearch Engine
|
Presearch Engine
|
||||||
================
|
================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.presearch
|
.. automodule:: searx.engines.presearch
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Recoll Engine
|
Recoll Engine
|
||||||
=============
|
=============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.recoll
|
.. automodule:: searx.engines.recoll
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Soundcloud
|
Soundcloud
|
||||||
==========
|
==========
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.soundcloud
|
.. automodule:: searx.engines.soundcloud
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Startpage Engines
|
Startpage Engines
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.startpage
|
.. automodule:: searx.engines.startpage
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Torznab WebAPI
|
Torznab WebAPI
|
||||||
==============
|
==============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.torznab
|
.. automodule:: searx.engines.torznab
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Wallhaven
|
Wallhaven
|
||||||
=========
|
=========
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.wallhaven
|
.. automodule:: searx.engines.wallhaven
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Wikimedia
|
Wikimedia
|
||||||
=========
|
=========
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
.. _wikipedia engine:
|
.. _wikipedia engine:
|
||||||
|
|
||||||
Wikipedia
|
Wikipedia
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Yacy
|
Yacy
|
||||||
====
|
====
|
||||||
|
|
||||||
.. contents:: Contents
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.yacy
|
.. automodule:: searx.engines.yacy
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -4,10 +4,5 @@
|
|||||||
Yahoo Engine
|
Yahoo Engine
|
||||||
============
|
============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.yahoo
|
.. automodule:: searx.engines.yahoo
|
||||||
:members:
|
:members:
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
XPath Engine
|
XPath Engine
|
||||||
============
|
============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.engines.xpath
|
.. automodule:: searx.engines.xpath
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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]`_.
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
Bot Detection
|
Bot Detection
|
||||||
=============
|
=============
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.botdetection
|
.. automodule:: searx.botdetection
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,6 @@
|
|||||||
Locales
|
Locales
|
||||||
=======
|
=======
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. automodule:: searx.locales
|
.. automodule:: searx.locales
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,6 @@
|
|||||||
Search processors
|
Search processors
|
||||||
=================
|
=================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 2
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
|
|
||||||
Abstract processor class
|
Abstract processor class
|
||||||
========================
|
========================
|
||||||
|
|
||||||
|
|||||||
@@ -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() %}
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
User information
|
User information
|
||||||
================
|
================
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:depth: 3
|
|
||||||
:local:
|
|
||||||
:backlinks: entry
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:maxdepth: 2
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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}")
|
||||||
|
|||||||
@@ -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": {
|
||||||
|
|||||||
@@ -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
|
||||||
===========================
|
===========================
|
||||||
|
|||||||
@@ -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 = []
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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"):
|
||||||
|
|||||||
+118
-75
@@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
"""This module implements the Wikidata engine. Some implementations are shared
|
"""This module implements the Wikidata engine.
|
||||||
from :ref:`wikipedia engine`.
|
|
||||||
|
|
||||||
|
Some implementations are shared from :ref:`wikipedia engine`.
|
||||||
"""
|
"""
|
||||||
# pylint: disable=missing-class-docstring
|
# pylint: disable=missing-class-docstring
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ from json import loads
|
|||||||
from dateutil.parser import isoparse
|
from dateutil.parser import isoparse
|
||||||
from babel.dates import format_datetime, format_date, format_time, get_datetime_format
|
from babel.dates import format_datetime, format_date, format_time, get_datetime_format
|
||||||
|
|
||||||
|
from searx.enginelib import EngineCache
|
||||||
from searx.data import WIKIDATA_UNITS
|
from searx.data import WIKIDATA_UNITS
|
||||||
from searx.network import post, get
|
from searx.network import post, get
|
||||||
from searx.utils import searxng_useragent, get_string_replaces_function
|
from searx.utils import searxng_useragent, get_string_replaces_function
|
||||||
@@ -44,11 +45,15 @@ display_type = ["infobox"]
|
|||||||
one will add a hit to the result list. The first one will show a hit in the
|
one will add a hit to the result list. The first one will show a hit in the
|
||||||
info box. Both values can be set, or one of the two can be set."""
|
info box. Both values can be set, or one of the two can be set."""
|
||||||
|
|
||||||
|
CACHE: EngineCache
|
||||||
|
"""Persistent (SQLite) key/value cache that deletes its values after ``expire``
|
||||||
|
seconds."""
|
||||||
|
|
||||||
# SPARQL
|
# SPARQL
|
||||||
SPARQL_ENDPOINT_URL = "https://query.wikidata.org/sparql"
|
SPARQL_ENDPOINT_URL = "https://query.wikidata.org/sparql"
|
||||||
SPARQL_EXPLAIN_URL = "https://query.wikidata.org/bigdata/namespace/wdq/sparql?explain"
|
SPARQL_EXPLAIN_URL = "https://query.wikidata.org/bigdata/namespace/wdq/sparql?explain"
|
||||||
WIKIDATA_PROPERTIES: dict[str | tuple[str, str], str] = {
|
WDPType = dict[str | tuple[str, str], str]
|
||||||
|
WIKIDATA_PROPERTIES: WDPType = {
|
||||||
"P434": "MusicBrainz",
|
"P434": "MusicBrainz",
|
||||||
"P435": "MusicBrainz",
|
"P435": "MusicBrainz",
|
||||||
"P436": "MusicBrainz",
|
"P436": "MusicBrainz",
|
||||||
@@ -140,13 +145,12 @@ replace_http_by_https = get_string_replaces_function({"http:": "https:"})
|
|||||||
|
|
||||||
|
|
||||||
class WDAttribute:
|
class WDAttribute:
|
||||||
__slots__ = ("name",)
|
|
||||||
|
|
||||||
def __init__(self, name: str):
|
def __init__(self, name: str):
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
|
|
||||||
def get_select(self):
|
def get_select(self):
|
||||||
return "(group_concat(distinct ?{name};separator=", ") as ?{name}s)".replace("{name}", self.name)
|
return "(group_concat(distinct ?{name};separator=', ') as ?{name}s)".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_label(self, language: str):
|
def get_label(self, language: str):
|
||||||
return get_label_for_entity(self.name, language)
|
return get_label_for_entity(self.name, language)
|
||||||
@@ -154,13 +158,13 @@ class WDAttribute:
|
|||||||
def get_where(self):
|
def get_where(self):
|
||||||
return "OPTIONAL { ?item wdt:{name} ?{name} . }".replace("{name}", self.name)
|
return "OPTIONAL { ?item wdt:{name} ?{name} . }".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_wikibase_label(self):
|
def get_wikibase_label(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_group_by(self):
|
def get_group_by(self) -> str:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def get_str(self, result: dict[str, t.Any], language: str): # pylint: disable=unused-argument
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None: # pylint: disable=unused-argument
|
||||||
return result.get(self.name + "s")
|
return result.get(self.name + "s")
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@@ -168,7 +172,7 @@ class WDAttribute:
|
|||||||
|
|
||||||
|
|
||||||
class WDAmountAttribute(WDAttribute):
|
class WDAmountAttribute(WDAttribute):
|
||||||
def get_select(self):
|
def get_select(self) -> str:
|
||||||
return "?{name} ?{name}Unit".replace("{name}", self.name)
|
return "?{name} ?{name}Unit".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_where(self):
|
def get_where(self):
|
||||||
@@ -178,21 +182,21 @@ class WDAmountAttribute(WDAttribute):
|
|||||||
'{name}', self.name
|
'{name}', self.name
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_group_by(self):
|
def get_group_by(self) -> str:
|
||||||
return self.get_select()
|
return self.get_select()
|
||||||
|
|
||||||
def get_str(self, result: dict[str, t.Any], language: str):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
value = result.get(self.name)
|
value: str | None = result.get(self.name)
|
||||||
unit = result.get(self.name + "Unit")
|
unit: str | None = result.get(self.name + "Unit")
|
||||||
if unit is not None:
|
if unit is not None:
|
||||||
unit = unit.replace("http://www.wikidata.org/entity/", "")
|
unit = unit.replace("http://www.wikidata.org/entity/", "")
|
||||||
return value + " " + get_label_for_entity(unit, language)
|
return str(value) + " " + get_label_for_entity(unit, language)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
class WDArticle(WDAttribute):
|
class WDArticle(WDAttribute):
|
||||||
|
|
||||||
def __init__(self, language: str, kwargs=None):
|
def __init__(self, language: str, kwargs: dict[str, t.Any] | None = None):
|
||||||
super().__init__("wikipedia")
|
super().__init__("wikipedia")
|
||||||
self.language: str = language
|
self.language: str = language
|
||||||
self.kwargs: dict[str, t.Any] = kwargs or {}
|
self.kwargs: dict[str, t.Any] = kwargs or {}
|
||||||
@@ -215,28 +219,28 @@ class WDArticle(WDAttribute):
|
|||||||
def get_group_by(self):
|
def get_group_by(self):
|
||||||
return self.get_select()
|
return self.get_select()
|
||||||
|
|
||||||
def get_str(self, result, language: str):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
key = "article{language}".replace("{language}", self.language)
|
key = "article{language}".replace("{language}", self.language)
|
||||||
return result.get(key)
|
return result.get(key)
|
||||||
|
|
||||||
|
|
||||||
class WDLabelAttribute(WDAttribute):
|
class WDLabelAttribute(WDAttribute):
|
||||||
def get_select(self):
|
def get_select(self):
|
||||||
return "(group_concat(distinct ?{name}Label;separator=", ") as ?{name}Labels)".replace("{name}", self.name)
|
return "(group_concat(distinct ?{name}Label;separator=', ') as ?{name}Labels)".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_where(self):
|
def get_where(self):
|
||||||
return "OPTIONAL { ?item wdt:{name} ?{name} . }".replace("{name}", self.name)
|
return "OPTIONAL { ?item wdt:{name} ?{name} . }".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_wikibase_label(self):
|
def get_wikibase_label(self) -> str:
|
||||||
return "?{name} rdfs:label ?{name}Label .".replace("{name}", self.name)
|
return "?{name} rdfs:label ?{name}Label .".replace("{name}", self.name)
|
||||||
|
|
||||||
def get_str(self, result, language):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
return result.get(self.name + "Labels")
|
return result.get(self.name + "Labels")
|
||||||
|
|
||||||
|
|
||||||
class WDURLAttribute(WDAttribute):
|
class WDURLAttribute(WDAttribute):
|
||||||
|
|
||||||
HTTP_WIKIMEDIA_IMAGE = "http://commons.wikimedia.org/wiki/Special:FilePath/"
|
HTTP_WIKIMEDIA_IMAGE: str = "http://commons.wikimedia.org/wiki/Special:FilePath/"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -265,12 +269,12 @@ class WDURLAttribute(WDAttribute):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
super().__init__(name)
|
super().__init__(name)
|
||||||
self.url_id = url_id
|
self.url_id: str | None = url_id
|
||||||
self.url_path_prefix = url_path_prefix
|
self.url_path_prefix: str | None = url_path_prefix
|
||||||
self.kwargs = kwargs
|
self.kwargs: dict[str, t.Any] = kwargs or {}
|
||||||
|
|
||||||
def get_str(self, result, language: str):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
value = result.get(self.name + "s")
|
value: str | None = result.get(self.name + "s")
|
||||||
if not value:
|
if not value:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -306,16 +310,16 @@ class WDGeoAttribute(WDAttribute):
|
|||||||
def get_group_by(self):
|
def get_group_by(self):
|
||||||
return self.get_select()
|
return self.get_select()
|
||||||
|
|
||||||
def get_str(self, result, language: str):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
latitude = result.get(self.name + "Lat")
|
latitude: str | None = result.get(self.name + "Lat")
|
||||||
longitude = result.get(self.name + "Long")
|
longitude: str | None = result.get(self.name + "Long")
|
||||||
if latitude and longitude:
|
if latitude and longitude:
|
||||||
return latitude + " " + longitude
|
return latitude + " " + longitude
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_geo_url(self, result, osm_zoom=19):
|
def get_geo_url(self, result: dict[str, t.Any], osm_zoom: int = 19) -> str | None:
|
||||||
latitude = result.get(self.name + "Lat")
|
latitude: str | None = result.get(self.name + "Lat")
|
||||||
longitude = result.get(self.name + "Long")
|
longitude: str | None = result.get(self.name + "Long")
|
||||||
if latitude and longitude:
|
if latitude and longitude:
|
||||||
return get_earth_coordinates_url(latitude, longitude, osm_zoom)
|
return get_earth_coordinates_url(latitude, longitude, osm_zoom)
|
||||||
return None
|
return None
|
||||||
@@ -323,9 +327,9 @@ class WDGeoAttribute(WDAttribute):
|
|||||||
|
|
||||||
class WDImageAttribute(WDURLAttribute):
|
class WDImageAttribute(WDURLAttribute):
|
||||||
|
|
||||||
def __init__(self, name, url_id=None, priority=100):
|
def __init__(self, name: str, url_id: str | None = None, priority: int = 100):
|
||||||
super().__init__(name, url_id)
|
super().__init__(name, url_id)
|
||||||
self.priority = priority
|
self.priority: int = priority
|
||||||
|
|
||||||
|
|
||||||
class WDDateAttribute(WDAttribute):
|
class WDDateAttribute(WDAttribute):
|
||||||
@@ -349,11 +353,11 @@ class WDDateAttribute(WDAttribute):
|
|||||||
def get_group_by(self):
|
def get_group_by(self):
|
||||||
return self.get_select()
|
return self.get_select()
|
||||||
|
|
||||||
def format_8(self, value, locale: str): # pylint: disable=unused-argument
|
def format_8(self, value: str, locale: str) -> str: # pylint: disable=unused-argument
|
||||||
# precision: less than a year
|
# precision: less than a year
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def format_9(self, value, locale: str):
|
def format_9(self, value: str, locale: str) -> str:
|
||||||
year = int(value)
|
year = int(value)
|
||||||
# precision: year
|
# precision: year
|
||||||
if year < 1584:
|
if year < 1584:
|
||||||
@@ -363,17 +367,17 @@ class WDDateAttribute(WDAttribute):
|
|||||||
timestamp = isoparse(value)
|
timestamp = isoparse(value)
|
||||||
return format_date(timestamp, format="yyyy", locale=locale)
|
return format_date(timestamp, format="yyyy", locale=locale)
|
||||||
|
|
||||||
def format_10(self, value, locale: str):
|
def format_10(self, value: str, locale: str) -> str:
|
||||||
# precision: month
|
# precision: month
|
||||||
timestamp = isoparse(value)
|
timestamp = isoparse(value)
|
||||||
return format_date(timestamp, format="MMMM y", locale=locale)
|
return format_date(timestamp, format="MMMM y", locale=locale)
|
||||||
|
|
||||||
def format_11(self, value, locale: str):
|
def format_11(self, value: str, locale: str) -> str:
|
||||||
# precision: day
|
# precision: day
|
||||||
timestamp = isoparse(value)
|
timestamp = isoparse(value)
|
||||||
return format_date(timestamp, format="full", locale=locale)
|
return format_date(timestamp, format="full", locale=locale)
|
||||||
|
|
||||||
def format_13(self, value, locale: str):
|
def format_13(self, value: str, locale: str) -> str:
|
||||||
timestamp = isoparse(value)
|
timestamp = isoparse(value)
|
||||||
# precision: minute
|
# precision: minute
|
||||||
return (
|
return (
|
||||||
@@ -383,11 +387,11 @@ class WDDateAttribute(WDAttribute):
|
|||||||
.replace("{1}", format_date(timestamp, "short", locale=locale))
|
.replace("{1}", format_date(timestamp, "short", locale=locale))
|
||||||
)
|
)
|
||||||
|
|
||||||
def format_14(self, value, locale):
|
def format_14(self, value: str, locale: str) -> str:
|
||||||
# precision: second.
|
# precision: second.
|
||||||
return format_datetime(isoparse(value), format="full", locale=locale)
|
return format_datetime(isoparse(value), format="full", locale=locale)
|
||||||
|
|
||||||
DATE_FORMAT = {
|
DATE_FORMAT: dict[str, tuple[str, int]] = {
|
||||||
"0": ("format_8", 1000000000),
|
"0": ("format_8", 1000000000),
|
||||||
"1": ("format_8", 100000000),
|
"1": ("format_8", 100000000),
|
||||||
"2": ("format_8", 10000000),
|
"2": ("format_8", 10000000),
|
||||||
@@ -405,15 +409,15 @@ class WDDateAttribute(WDAttribute):
|
|||||||
"14": ("format_14", 0), # second
|
"14": ("format_14", 0), # second
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_str(self, result, language):
|
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||||
value = result.get(self.name)
|
value: str | None = result.get(self.name)
|
||||||
if value == "" or value is None:
|
if value == "" or value is None:
|
||||||
return None
|
return None
|
||||||
precision = result.get(self.name + "timePrecision")
|
_p: str = result.get(self.name + "timePrecision") or "1"
|
||||||
date_format = WDDateAttribute.DATE_FORMAT.get(precision)
|
date_format = WDDateAttribute.DATE_FORMAT.get(_p)
|
||||||
if date_format is not None:
|
if date_format is not None:
|
||||||
format_method = getattr(self, date_format[0])
|
format_method = getattr(self, date_format[0])
|
||||||
precision = date_format[1]
|
precision: int = date_format[1]
|
||||||
try:
|
try:
|
||||||
if precision >= 1:
|
if precision >= 1:
|
||||||
_t = value.split("-")
|
_t = value.split("-")
|
||||||
@@ -427,9 +431,25 @@ class WDDateAttribute(WDAttribute):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
WDAttrType = (
|
||||||
|
WDAttribute
|
||||||
|
| WDAmountAttribute
|
||||||
|
| WDArticle
|
||||||
|
| WDLabelAttribute
|
||||||
|
| WDURLAttribute
|
||||||
|
| WDGeoAttribute
|
||||||
|
| WDImageAttribute
|
||||||
|
| WDDateAttribute
|
||||||
|
)
|
||||||
|
WDAttrList = list[WDAttrType]
|
||||||
|
|
||||||
|
|
||||||
def get_headers() -> dict[str, str]:
|
def get_headers() -> dict[str, str]:
|
||||||
# user agent: https://www.mediawiki.org/wiki/Wikidata_Query_Service/User_Manual#Query_limits
|
# user agent: https://www.mediawiki.org/wiki/Wikidata_Query_Service/User_Manual#Query_limits
|
||||||
return {"Accept": "application/sparql-results+json", "User-Agent": searxng_useragent()}
|
return {
|
||||||
|
"Accept": "application/sparql-results+json",
|
||||||
|
"User-Agent": f"wikidata engine - {searxng_useragent()}",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_label_for_entity(entity_id: str, language: str) -> str:
|
def get_label_for_entity(entity_id: str, language: str) -> str:
|
||||||
@@ -445,7 +465,7 @@ def get_label_for_entity(entity_id: str, language: str) -> str:
|
|||||||
return name
|
return name
|
||||||
|
|
||||||
|
|
||||||
def send_wikidata_query(query: str, method="GET", **kwargs) -> dict[str, t.Any]:
|
def send_wikidata_query(query: str, method: str = "GET", **kwargs: dict[str, t.Any]) -> dict[str, t.Any]:
|
||||||
if method == "GET":
|
if method == "GET":
|
||||||
# query will be cached by wikidata
|
# query will be cached by wikidata
|
||||||
http_response = get(SPARQL_ENDPOINT_URL + "?" + urlencode({"query": query}), headers=get_headers(), **kwargs)
|
http_response = get(SPARQL_ENDPOINT_URL + "?" + urlencode({"query": query}), headers=get_headers(), **kwargs)
|
||||||
@@ -461,15 +481,17 @@ def send_wikidata_query(query: str, method="GET", **kwargs) -> dict[str, t.Any]:
|
|||||||
|
|
||||||
def request(query: str, params: "OnlineParams") -> None:
|
def request(query: str, params: "OnlineParams") -> None:
|
||||||
|
|
||||||
attributes: tuple[str, list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute]]
|
attributes: WDAttrList
|
||||||
eng_tag, _wiki_netloc = get_wiki_params(params["searxng_locale"], traits)
|
eng_tag, _wiki_netloc = get_wiki_params(params["searxng_locale"], traits)
|
||||||
query, attributes = get_query(query, eng_tag)
|
query, attributes = get_query(query, eng_tag or "en")
|
||||||
logger.debug("request --> language %s // len(attributes): %s", eng_tag, len(attributes))
|
logger.debug("request --> language %s // len(attributes): %s", eng_tag, len(attributes))
|
||||||
|
|
||||||
params["method"] = "POST"
|
params["method"] = "POST"
|
||||||
params["url"] = SPARQL_ENDPOINT_URL
|
params["url"] = SPARQL_ENDPOINT_URL
|
||||||
params["data"] = {"query": query}
|
params["data"] = {"query": query}
|
||||||
params["headers"] = get_headers()
|
params["headers"] = get_headers()
|
||||||
|
|
||||||
|
# additional parameters (not a part of OnlineParams)
|
||||||
params["language"] = eng_tag # type: ignore
|
params["language"] = eng_tag # type: ignore
|
||||||
params["attributes"] = attributes # type: ignore
|
params["attributes"] = attributes # type: ignore
|
||||||
|
|
||||||
@@ -479,14 +501,16 @@ def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
|
|||||||
results: list[dict[str, t.Any]] = []
|
results: list[dict[str, t.Any]] = []
|
||||||
jsonresponse = loads(resp.content.decode())
|
jsonresponse = loads(resp.content.decode())
|
||||||
|
|
||||||
|
# additional parameters ..
|
||||||
language: str = resp.search_params["language"] # type: ignore
|
language: str = resp.search_params["language"] # type: ignore
|
||||||
attributes = resp.search_params["attributes"] # type: ignore
|
attributes: WDAttrList = resp.search_params["attributes"] # type: ignore
|
||||||
|
|
||||||
logger.debug("request --> language %s // len(attributes): %s", language, len(attributes))
|
logger.debug("request --> language %s // len(attributes): %s", language, len(attributes))
|
||||||
|
|
||||||
seen_entities: set[str] = set()
|
seen_entities: set[str] = set()
|
||||||
for result in jsonresponse.get("results", {}).get("bindings", []):
|
for result in jsonresponse.get("results", {}).get("bindings", []):
|
||||||
attribute_result = {key: value["value"] for key, value in result.items()}
|
attribute_result = {key: value["value"] for key, value in result.items()}
|
||||||
entity_url = attribute_result["item"]
|
entity_url: str = attribute_result["item"]
|
||||||
if entity_url not in seen_entities and entity_url not in DUMMY_ENTITY_URLS:
|
if entity_url not in seen_entities and entity_url not in DUMMY_ENTITY_URLS:
|
||||||
seen_entities.add(entity_url)
|
seen_entities.add(entity_url)
|
||||||
results += get_results(attribute_result, attributes, language)
|
results += get_results(attribute_result, attributes, language)
|
||||||
@@ -500,7 +524,7 @@ _IMG_SRC_DEFAULT_URL_PREFIX = "https://commons.wikimedia.org/wiki/Special:FilePa
|
|||||||
_IMG_SRC_NEW_URL_PREFIX = "https://upload.wikimedia.org/wikipedia/commons/thumb/"
|
_IMG_SRC_NEW_URL_PREFIX = "https://upload.wikimedia.org/wikipedia/commons/thumb/"
|
||||||
|
|
||||||
|
|
||||||
def get_thumbnail(img_src: str) -> str:
|
def get_thumbnail(img_src: str | None) -> str | None:
|
||||||
"""Get Thumbnail image from wikimedia commons
|
"""Get Thumbnail image from wikimedia commons
|
||||||
|
|
||||||
Images from commons.wikimedia.org are (HTTP) redirected to
|
Images from commons.wikimedia.org are (HTTP) redirected to
|
||||||
@@ -539,53 +563,58 @@ def get_thumbnail(img_src: str) -> str:
|
|||||||
return img_src
|
return img_src
|
||||||
|
|
||||||
|
|
||||||
def get_results(attribute_result: dict[str, t.Any], attributes, language):
|
def get_results(
|
||||||
|
attribute_result: dict[str, t.Any],
|
||||||
|
attributes: WDAttrList,
|
||||||
|
language: str,
|
||||||
|
):
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
results = []
|
results: list[dict[str, t.Any]] = []
|
||||||
infobox_title = attribute_result.get("itemLabel")
|
infobox_title: str = attribute_result.get("itemLabel") # pyright: ignore[reportAssignmentType]
|
||||||
infobox_id = attribute_result["item"]
|
infobox_id = attribute_result["item"]
|
||||||
infobox_id_lang = None
|
infobox_id_lang: str | None = None
|
||||||
infobox_urls = []
|
infobox_urls: list[dict[str, str]] = []
|
||||||
infobox_attributes = []
|
infobox_attributes: list[dict[str, str]] = []
|
||||||
infobox_content = attribute_result.get("itemDescription", [])
|
infobox_content = attribute_result.get("itemDescription", [])
|
||||||
img_src = None
|
img_src: str | None = None
|
||||||
img_src_priority = 0
|
img_src_priority = 0
|
||||||
|
|
||||||
for attribute in attributes:
|
for attribute in attributes:
|
||||||
value = attribute.get_str(attribute_result, language)
|
value: str | None = attribute.get_str(attribute_result, language)
|
||||||
if value is not None and value != "":
|
if value is not None and value != "":
|
||||||
attribute_type = type(attribute)
|
|
||||||
|
|
||||||
if attribute_type in (WDURLAttribute, WDArticle):
|
if isinstance(attribute, (WDURLAttribute, WDArticle)):
|
||||||
# get_select() method : there is group_concat(distinct ...;separator=", ")
|
# get_select() method : there is group_concat(distinct ...;separator=", ")
|
||||||
# split the value here
|
# split the value here
|
||||||
for url in value.split(", "):
|
for url in value.split(", "):
|
||||||
infobox_urls.append({"title": attribute.get_label(language), "url": url, **attribute.kwargs})
|
infobox_urls.append({"title": attribute.get_label(language), "url": url, **attribute.kwargs})
|
||||||
# "normal" results (not infobox) include official website and Wikipedia links.
|
# "normal" results (not infobox) include official website and Wikipedia links.
|
||||||
if "list" in display_type and (attribute.kwargs.get("official") or attribute_type == WDArticle):
|
if "list" in display_type and (
|
||||||
|
attribute.kwargs.get("official") or isinstance(attribute, WDArticle)
|
||||||
|
):
|
||||||
results.append({"title": infobox_title, "url": url, "content": infobox_content})
|
results.append({"title": infobox_title, "url": url, "content": infobox_content})
|
||||||
|
|
||||||
# update the infobox_id with the wikipedia URL
|
# update the infobox_id with the wikipedia URL
|
||||||
# first the local wikipedia URL, and as fallback the english wikipedia URL
|
# first the local wikipedia URL, and as fallback the english wikipedia URL
|
||||||
if attribute_type == WDArticle and (
|
if isinstance(attribute, WDArticle) and (
|
||||||
(attribute.language == "en" and infobox_id_lang is None) or attribute.language != "en"
|
(attribute.language == "en" and infobox_id_lang is None) or attribute.language != "en"
|
||||||
):
|
):
|
||||||
infobox_id_lang = attribute.language
|
infobox_id_lang = attribute.language
|
||||||
infobox_id = url
|
infobox_id = url
|
||||||
elif attribute_type == WDImageAttribute:
|
elif isinstance(attribute, WDImageAttribute):
|
||||||
# this attribute is an image.
|
# this attribute is an image.
|
||||||
# replace the current image only the priority is lower
|
# replace the current image only the priority is lower
|
||||||
# (the infobox contain only one image).
|
# (the infobox contain only one image).
|
||||||
if attribute.priority > img_src_priority:
|
if attribute.priority > img_src_priority:
|
||||||
img_src = get_thumbnail(value)
|
img_src = get_thumbnail(value)
|
||||||
img_src_priority = attribute.priority
|
img_src_priority = attribute.priority
|
||||||
elif attribute_type == WDGeoAttribute:
|
elif isinstance(attribute, WDGeoAttribute):
|
||||||
# geocoordinate link
|
# geocoordinate link
|
||||||
# use the area to get the OSM zoom
|
# use the area to get the OSM zoom
|
||||||
# Note: ignore the unit (must be km² otherwise the calculation is wrong)
|
# Note: ignore the unit (must be km² otherwise the calculation is wrong)
|
||||||
# Should use normalized value p:P2046/psn:P2046/wikibase:quantityAmount
|
# Should use normalized value p:P2046/psn:P2046/wikibase:quantityAmount
|
||||||
area = attribute_result.get("P2046")
|
area = attribute_result.get("P2046")
|
||||||
osm_zoom = area_to_osm_zoom(area) if area else 19
|
osm_zoom: int = area_to_osm_zoom(area) if area else 19
|
||||||
url = attribute.get_geo_url(attribute_result, osm_zoom=osm_zoom)
|
url = attribute.get_geo_url(attribute_result, osm_zoom=osm_zoom)
|
||||||
if url:
|
if url:
|
||||||
infobox_urls.append({"title": attribute.get_label(language), "url": url, "entity": attribute.name})
|
infobox_urls.append({"title": attribute.get_label(language), "url": url, "entity": attribute.name})
|
||||||
@@ -622,9 +651,7 @@ def get_results(attribute_result: dict[str, t.Any], attributes, language):
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def get_query(
|
def get_query(query: str, language: str) -> tuple[str, WDAttrList]:
|
||||||
query: str, language: str
|
|
||||||
) -> tuple[str, list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute]]:
|
|
||||||
attributes = get_attributes(language)
|
attributes = get_attributes(language)
|
||||||
select = [a.get_select() for a in attributes]
|
select = [a.get_select() for a in attributes]
|
||||||
where = list(filter(lambda s: len(s) > 0, [a.get_where() for a in attributes]))
|
where = list(filter(lambda s: len(s) > 0, [a.get_where() for a in attributes]))
|
||||||
@@ -643,7 +670,7 @@ def get_query(
|
|||||||
|
|
||||||
def get_attributes(language: str):
|
def get_attributes(language: str):
|
||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
attributes: list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute] = []
|
attributes: WDAttrList = []
|
||||||
|
|
||||||
def add_value(name: str):
|
def add_value(name: str):
|
||||||
attributes.append(WDAttribute(name))
|
attributes.append(WDAttribute(name))
|
||||||
@@ -654,7 +681,7 @@ def get_attributes(language: str):
|
|||||||
def add_label(name: str):
|
def add_label(name: str):
|
||||||
attributes.append(WDLabelAttribute(name))
|
attributes.append(WDLabelAttribute(name))
|
||||||
|
|
||||||
def add_url(name: str, url_id: str | None = None, url_path_prefix: str | None = None, **kwargs):
|
def add_url(name: str, url_id: str | None = None, url_path_prefix: str | None = None, **kwargs: dict[str, t.Any]):
|
||||||
attributes.append(WDURLAttribute(name, url_id, url_path_prefix, kwargs))
|
attributes.append(WDURLAttribute(name, url_id, url_path_prefix, kwargs))
|
||||||
|
|
||||||
def add_image(name: str, url_id: str | None = None, priority: int = 1):
|
def add_image(name: str, url_id: str | None = None, priority: int = 1):
|
||||||
@@ -749,7 +776,8 @@ def get_attributes(language: str):
|
|||||||
add_value("P498") # currency code (ISO 4217)
|
add_value("P498") # currency code (ISO 4217)
|
||||||
|
|
||||||
# URL
|
# URL
|
||||||
add_url("P856", official=True) # official website
|
kwargs: dict[str, t.Any] = {"official": True}
|
||||||
|
add_url("P856", **kwargs) # official website
|
||||||
attributes.append(WDArticle(language)) # wikipedia (user language)
|
attributes.append(WDArticle(language)) # wikipedia (user language)
|
||||||
if not language.startswith("en"):
|
if not language.startswith("en"):
|
||||||
attributes.append(WDArticle("en")) # wikipedia (english)
|
attributes.append(WDArticle("en")) # wikipedia (english)
|
||||||
@@ -796,7 +824,19 @@ def debug_explain_wikidata_query(query: str, method: str = "GET"):
|
|||||||
return http_response.content
|
return http_response.content
|
||||||
|
|
||||||
|
|
||||||
def init(engine_settings=None): # pylint: disable=unused-argument
|
def init(_):
|
||||||
|
global CACHE # pylint: disable=global-statement
|
||||||
|
CACHE = EngineCache("wikidata")
|
||||||
|
init_wikidata_properties()
|
||||||
|
|
||||||
|
|
||||||
|
def init_wikidata_properties():
|
||||||
|
global WIKIDATA_PROPERTIES # pylint: disable=global-statement
|
||||||
|
p: WDPType = CACHE.get(key="WIKIDATA_PROPERTIES")
|
||||||
|
if p:
|
||||||
|
WIKIDATA_PROPERTIES = p
|
||||||
|
return
|
||||||
|
|
||||||
# WIKIDATA_PROPERTIES : add unit symbols
|
# WIKIDATA_PROPERTIES : add unit symbols
|
||||||
for k, v in WIKIDATA_UNITS.items():
|
for k, v in WIKIDATA_UNITS.items():
|
||||||
WIKIDATA_PROPERTIES[k] = v["symbol"]
|
WIKIDATA_PROPERTIES[k] = v["symbol"]
|
||||||
@@ -808,7 +848,8 @@ def init(engine_settings=None): # pylint: disable=unused-argument
|
|||||||
if attribute.name not in WIKIDATA_PROPERTIES:
|
if attribute.name not in WIKIDATA_PROPERTIES:
|
||||||
wikidata_property_names.append("wd:" + attribute.name)
|
wikidata_property_names.append("wd:" + attribute.name)
|
||||||
query = QUERY_PROPERTY_NAMES.replace("%ATTRIBUTES%", " ".join(wikidata_property_names))
|
query = QUERY_PROPERTY_NAMES.replace("%ATTRIBUTES%", " ".join(wikidata_property_names))
|
||||||
jsonresponse = send_wikidata_query(query, timeout=20)
|
kwargs: dict[str, t.Any] = {"timeout": 20}
|
||||||
|
jsonresponse = send_wikidata_query(query, **kwargs)
|
||||||
for result in jsonresponse.get("results", {}).get("bindings", {}):
|
for result in jsonresponse.get("results", {}).get("bindings", {}):
|
||||||
name_field = result.get("name")
|
name_field = result.get("name")
|
||||||
if not name_field:
|
if not name_field:
|
||||||
@@ -818,6 +859,8 @@ def init(engine_settings=None): # pylint: disable=unused-argument
|
|||||||
entity_id = result["item"]["value"].replace("http://www.wikidata.org/entity/", "")
|
entity_id = result["item"]["value"].replace("http://www.wikidata.org/entity/", "")
|
||||||
WIKIDATA_PROPERTIES[(entity_id, lang)] = name.capitalize()
|
WIKIDATA_PROPERTIES[(entity_id, lang)] = name.capitalize()
|
||||||
|
|
||||||
|
CACHE.set(key="WIKIDATA_PROPERTIES", value=WIKIDATA_PROPERTIES)
|
||||||
|
|
||||||
|
|
||||||
def fetch_traits(engine_traits: EngineTraits):
|
def fetch_traits(engine_traits: EngineTraits):
|
||||||
"""Uses languages evaluated from :py:obj:`wikipedia.fetch_wikimedia_traits
|
"""Uses languages evaluated from :py:obj:`wikipedia.fetch_wikimedia_traits
|
||||||
|
|||||||
+12
-11
@@ -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"]}',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+81
-1
@@ -1,14 +1,17 @@
|
|||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
"""Yep (general, images, news)"""
|
"""Yep (general, images, news)"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
import typing as t
|
import typing as t
|
||||||
|
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from searx.result_types import EngineResults
|
from searx.result_types import EngineResults
|
||||||
from searx.utils import html_to_text
|
from searx.utils import html_to_text, eval_xpath_getindex, extract_text
|
||||||
|
|
||||||
if t.TYPE_CHECKING:
|
if t.TYPE_CHECKING:
|
||||||
|
from searx.enginelib.traits import EngineTraits
|
||||||
from searx.extended_types import SXNG_Response
|
from searx.extended_types import SXNG_Response
|
||||||
from searx.search.processors import OnlineParams
|
from searx.search.processors import OnlineParams
|
||||||
|
|
||||||
@@ -29,9 +32,17 @@ enable_http2 = False
|
|||||||
|
|
||||||
results_per_page = 20
|
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:
|
def request(query: str, params: 'OnlineParams') -> None:
|
||||||
args = {'query': query, 'safeSearch': safesearch_map[params['safesearch']], 'limit': results_per_page}
|
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
|
||||||
|
|
||||||
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'
|
||||||
@@ -50,3 +61,72 @@ def response(resp: 'SXNG_Response') -> EngineResults:
|
|||||||
)
|
)
|
||||||
|
|
||||||
return res
|
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
|
||||||
|
|||||||
@@ -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
-7
@@ -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
|
||||||
@@ -1203,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
|
||||||
@@ -1210,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
|
||||||
@@ -2149,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
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"DH1EQbEY.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/assertElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntype AssertElement = <T>(element?: T | null) => asserts element is T;\nexport const assertElement: AssertElement = <T>(element?: T | null): asserts element is T => {\n if (!element) {\n throw new Error(\"DOM element not found\");\n }\n};\n"],"mappings":"AAGA,IAAa,EAAmC,GAA6C,CAC3F,GAAI,CAAC,EACH,MAAU,MAAM,wBAAwB"}
|
{"version":3,"file":"DH1EQbEY.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/assertElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntype AssertElement = <T>(element?: T | null) => asserts element is T;\nexport const assertElement: AssertElement = <T>(element?: T | null): asserts element is T => {\n if (!element) {\n throw new Error(\"DOM element not found\");\n }\n};\n"],"mappings":"AAGA,IAAa,EAAmC,GAA6C,CAC3F,GAAI,CAAC,EACH,MAAU,MAAM,uBAAuB,CAE3C"}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user