mirror of
https://github.com/searxng/searxng.git
synced 2026-05-22 10:54:30 +02:00
Compare commits
33 Commits
36bcd6b551
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b9340f50c2 | |||
| d3deacc6d4 | |||
| d8f74af3d1 | |||
| 24b1a1b6a8 | |||
| 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 | |||
| 330d56bba9 |
@@ -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
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
.. _500px engine:
|
||||||
|
|
||||||
|
=====
|
||||||
|
500px
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. automodule:: searx.engines.500px
|
||||||
|
:members:
|
||||||
@@ -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
|
||||||
===========================
|
===========================
|
||||||
@@ -159,7 +160,8 @@ class EngineCache:
|
|||||||
def __init__(self, engine_name: str, expire: int | None = None):
|
def __init__(self, engine_name: str, expire: int | None = None):
|
||||||
self.expire: int = expire or ENGINES_CACHE.cfg.MAXHOLD_TIME
|
self.expire: int = expire or ENGINES_CACHE.cfg.MAXHOLD_TIME
|
||||||
_valid = "-_." + string.ascii_letters + string.digits
|
_valid = "-_." + string.ascii_letters + string.digits
|
||||||
self.table_name: str = "".join([c if c in _valid else "_" for c in engine_name])
|
# engine_name is a table and SQL table names must start with a letter
|
||||||
|
self.table_name: str = "eng_" + "".join([c if c in _valid else "_" for c in engine_name])
|
||||||
|
|
||||||
def set(self, key: str, value: t.Any, expire: int | None = None) -> bool:
|
def set(self, key: str, value: t.Any, expire: int | None = None) -> bool:
|
||||||
return ENGINES_CACHE.set(
|
return ENGINES_CACHE.set(
|
||||||
|
|||||||
@@ -116,19 +116,6 @@ class EngineTraits:
|
|||||||
return self.all_locale
|
return self.all_locale
|
||||||
return locales.get_engine_locale(searxng_locale, self.regions, default=default)
|
return locales.get_engine_locale(searxng_locale, self.regions, default=default)
|
||||||
|
|
||||||
def is_locale_supported(self, searxng_locale: str) -> bool:
|
|
||||||
"""A *locale* (SearXNG's internal representation) is considered to be
|
|
||||||
supported by the engine if the *region* or the *language* is supported
|
|
||||||
by the engine.
|
|
||||||
|
|
||||||
For verification the functions :py:func:`EngineTraits.get_region` and
|
|
||||||
:py:func:`EngineTraits.get_language` are used.
|
|
||||||
"""
|
|
||||||
if self.data_type == "traits_v1":
|
|
||||||
return bool(self.get_region(searxng_locale) or self.get_language(searxng_locale))
|
|
||||||
|
|
||||||
raise TypeError("engine traits of type %s is unknown" % self.data_type)
|
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
"""Create a copy of the dataclass object."""
|
"""Create a copy of the dataclass object."""
|
||||||
return EngineTraits(**dataclasses.asdict(self))
|
return EngineTraits(**dataclasses.asdict(self))
|
||||||
|
|||||||
@@ -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 = []
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
# pylint: disable=invalid-name
|
||||||
|
"""500px_ is a online network for photographers with millions of members
|
||||||
|
worldwide. Photographers come to 500px to discover and share incredible photos,
|
||||||
|
gain meaningful exposure, compete in photo contests, and license their photos
|
||||||
|
through our exclusive distribution partners.
|
||||||
|
|
||||||
|
.. _500px: https://500px.com
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
"website": "https://500px.com",
|
||||||
|
"wikidata_id": "Q354894",
|
||||||
|
"official_api_documentation": None,
|
||||||
|
"use_official_api": False,
|
||||||
|
"require_api_key": False,
|
||||||
|
"results": "JSON",
|
||||||
|
}
|
||||||
|
|
||||||
|
base_url = "https://500px.com"
|
||||||
|
api_url = "https://api.500px.com"
|
||||||
|
|
||||||
|
categories = ["images"]
|
||||||
|
|
||||||
|
paging = True
|
||||||
|
results_per_page = 30
|
||||||
|
"""Number of results to return in the request.
|
||||||
|
|
||||||
|
The default was taken from the WEB UI, where the GraphQL query sets the value to
|
||||||
|
*static*: ``first: 30``.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
SXNG_query = """query PhotoSearchPaginationContainerQuery(
|
||||||
|
$first: Int, $cursor: String, $search: String!, $sort: PhotoSort, $filters: [PhotoSearchFilter!], $nlp: Boolean
|
||||||
|
) {
|
||||||
|
...SXNG_query
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment SXNG_query on Query {
|
||||||
|
photoSearch(sort: $sort, first: $first, after: $cursor, search: $search, filters: $filters, nlp: $nlp) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
canonicalPath
|
||||||
|
name
|
||||||
|
description
|
||||||
|
width
|
||||||
|
height
|
||||||
|
photographer: uploader {
|
||||||
|
displayName
|
||||||
|
}
|
||||||
|
images(sizes: [35, 33]) {
|
||||||
|
size
|
||||||
|
url
|
||||||
|
jpegUrl
|
||||||
|
webpUrl
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def setup(_) -> bool:
|
||||||
|
global SXNG_query # pylint: disable=global-statement
|
||||||
|
rand_str: str = "".join(random.choice(string.ascii_letters) for _ in range(5))
|
||||||
|
SXNG_query = SXNG_query.replace("SXNG_query", "PhotoSearchPaginationContainer_query_1" + rand_str)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def request(query: str, params: "OnlineParams") -> None:
|
||||||
|
# cursor is the base64 hash of the string "pos-<offset-1>", e.g. "pos-29" -> "cG9zLTI5"
|
||||||
|
offset = ((params["pageno"] - 1) * results_per_page) - 1
|
||||||
|
cursor = codecs.encode(f"pos-{offset}".encode("utf-8"), "base64").decode("utf-8")
|
||||||
|
|
||||||
|
params["url"] = f"{api_url}/graphql"
|
||||||
|
params["method"] = "POST"
|
||||||
|
params["json"] = {
|
||||||
|
"operationName": "PhotoSearchPaginationContainerQuery",
|
||||||
|
"variables": {
|
||||||
|
"first": results_per_page,
|
||||||
|
"cursor": cursor,
|
||||||
|
"search": query,
|
||||||
|
"sort": "RELEVANCE",
|
||||||
|
"filters": [],
|
||||||
|
"nlp": False,
|
||||||
|
},
|
||||||
|
"query": SXNG_query,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def response(resp: "SXNG_Response"):
|
||||||
|
res = EngineResults()
|
||||||
|
json_data = resp.json()["data"]["photoSearch"]
|
||||||
|
|
||||||
|
for edge in json_data["edges"]:
|
||||||
|
node = edge["node"] # pyright: ignore[reportAny]
|
||||||
|
if not node["images"]:
|
||||||
|
continue
|
||||||
|
images: list[dict[str, str]] = sorted(node["images"], key=lambda i: i["size"])
|
||||||
|
thumbnail_src = images[0]["url"]
|
||||||
|
img_src = images[-1]["url"]
|
||||||
|
res.add(
|
||||||
|
res.types.LegacyResult(
|
||||||
|
{
|
||||||
|
"template": "images.html",
|
||||||
|
"url": base_url + node["canonicalPath"],
|
||||||
|
"thumbnail_src": thumbnail_src,
|
||||||
|
"img_src": img_src,
|
||||||
|
"title": node["name"],
|
||||||
|
"content": node["description"],
|
||||||
|
"author": node["photographer"]["displayName"],
|
||||||
|
"resolution": f"{node['width']}x{node['height']}",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return res
|
||||||
@@ -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
|
||||||
+31
-24
@@ -1,15 +1,23 @@
|
|||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
"""Fyyd (podcasts)"""
|
"""Fyyd (podcasts)"""
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
|
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 = {
|
||||||
'website': 'https://fyyd.de',
|
"website": "https://fyyd.de",
|
||||||
'official_api_documentation': 'https://github.com/eazyliving/fyyd-api',
|
"official_api_documentation": "https://github.com/eazyliving/fyyd-api",
|
||||||
'use_official_api': True,
|
"use_official_api": True,
|
||||||
'require_api_key': False,
|
"require_api_key": False,
|
||||||
'results': 'JSON',
|
"results": "JSON",
|
||||||
}
|
}
|
||||||
categories = []
|
categories = []
|
||||||
paging = True
|
paging = True
|
||||||
@@ -18,31 +26,30 @@ base_url = "https://api.fyyd.de"
|
|||||||
page_size = 10
|
page_size = 10
|
||||||
|
|
||||||
|
|
||||||
def request(query, params):
|
def request(query: str, params: "OnlineParams") -> None:
|
||||||
args = {
|
args = {
|
||||||
'term': query,
|
"term": query,
|
||||||
'count': page_size,
|
"count": page_size,
|
||||||
'page': params['pageno'] - 1,
|
"page": params["pageno"] - 1,
|
||||||
}
|
}
|
||||||
params['url'] = f"{base_url}/0.2/search/podcast?{urlencode(args)}"
|
params["url"] = f"{base_url}/0.2/search/podcast?{urlencode(args)}"
|
||||||
return params
|
|
||||||
|
|
||||||
|
|
||||||
def response(resp):
|
def response(resp: "SXNG_Response"):
|
||||||
results = []
|
res = EngineResults()
|
||||||
|
|
||||||
json_results = resp.json()['data']
|
json_results: list[dict[str, str]] = resp.json()["data"] # pyright: ignore[reportAny]
|
||||||
|
|
||||||
for result in json_results:
|
for result in json_results:
|
||||||
results.append(
|
res.add(
|
||||||
{
|
res.types.MainResult(
|
||||||
'url': result['htmlURL'],
|
url=result["htmlURL"],
|
||||||
'title': result['title'],
|
title=result["title"],
|
||||||
'content': result['description'],
|
content=result["description"],
|
||||||
'thumbnail': result['smallImageURL'],
|
thumbnail=result["smallImageURL"],
|
||||||
'publishedDate': datetime.strptime(result['status_since'], '%Y-%m-%d %H:%M:%S'),
|
publishedDate=datetime.strptime(result["status_since"], "%Y-%m-%d %H:%M:%S"),
|
||||||
'metadata': f"Rank: {result['rank']} || {result['episode_count']} episodes",
|
metadata=f"Rank: {result['rank']} || {result['episode_count']} episodes",
|
||||||
}
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return results
|
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
|
||||||
|
|||||||
+18
-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
|
||||||
@@ -310,6 +310,12 @@ engines:
|
|||||||
shortcut: 360sov
|
shortcut: 360sov
|
||||||
disabled: true
|
disabled: true
|
||||||
|
|
||||||
|
- name: 500px
|
||||||
|
engine: 500px
|
||||||
|
shortcut: "500"
|
||||||
|
disabled: true
|
||||||
|
timeout: 5
|
||||||
|
|
||||||
- name: 9gag
|
- name: 9gag
|
||||||
engine: 9gag
|
engine: 9gag
|
||||||
shortcut: 9g
|
shortcut: 9g
|
||||||
@@ -469,11 +475,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 +601,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 +1209,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 +1217,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 +2159,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"}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user