mirror of
https://github.com/searxng/searxng.git
synced 2026-05-29 22:24:13 +02:00
Compare commits
53 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cdc96d0b4f | |||
| 4ea5c57a84 | |||
| 6917395dc1 | |||
| 128e28fe3f | |||
| fb3ed5b081 | |||
| 4ebe6b90d6 | |||
| 0657217a3e | |||
| 0037d43d87 | |||
| f5be39e245 | |||
| 1574939441 | |||
| f1a22dec9e | |||
| 3db8b424a8 | |||
| a16a3dedb4 | |||
| c629dd4f3c | |||
| 28ef4f7447 | |||
| cb4b70ac50 | |||
| e29e861e2c | |||
| 89b89a88fe | |||
| 46071a011a | |||
| b0d8af96bf | |||
| dd27fce3b7 | |||
| efc305b7f9 | |||
| 323ce76004 | |||
| dfc2da707b | |||
| fc90c5b09c | |||
| c57f772ad0 | |||
| b8498d7891 | |||
| d791a3906a | |||
| 295e0bffaf | |||
| b9340f50c2 | |||
| d3deacc6d4 | |||
| d8f74af3d1 | |||
| 24b1a1b6a8 | |||
| d7e8b7cd18 | |||
| f26e450778 | |||
| dce3bb69bb | |||
| de49d27846 | |||
| 16a7537bfd | |||
| afafca93f3 | |||
| 240f403d93 | |||
| 9b30ae005b | |||
| 790683bbd7 | |||
| 52b446b4ad | |||
| 6cee4b8947 | |||
| 8e5aa9d394 | |||
| cf4d7e31c4 | |||
| 471f2b205f | |||
| 09829b1ccc | |||
| df1f24fb7f | |||
| 0cba32c15f | |||
| 849e17e431 | |||
| d8ab61a9e0 | |||
| 7eb130b1a8 |
@@ -29,7 +29,7 @@ jobs:
|
||||
persist-credentials: "false"
|
||||
|
||||
- name: Sync GHCS from Docker Scout
|
||||
uses: docker/scout-action@bacf462e8d090c09660de30a6ccc718035f961e3 # v1.20.4
|
||||
uses: docker/scout-action@cd72f264beff1cd72735de31148b9d3244a0234a # v1.21.0
|
||||
with:
|
||||
organization: "searxng"
|
||||
dockerhub-user: "${{ secrets.DOCKER_USER }}"
|
||||
@@ -41,6 +41,6 @@ jobs:
|
||||
write-comment: "false"
|
||||
|
||||
- name: Upload SARIFs
|
||||
uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2
|
||||
uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
|
||||
with:
|
||||
sarif_file: "./scout.sarif"
|
||||
|
||||
Generated
+140
-151
@@ -15,8 +15,8 @@
|
||||
"swiped-events": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.4.13",
|
||||
"@types/node": "^25.6.0",
|
||||
"@biomejs/biome": "2.4.15",
|
||||
"@types/node": "^25.8.0",
|
||||
"browserslist": "^4.28.2",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
"edge.js": "^6.5.0",
|
||||
@@ -24,12 +24,12 @@
|
||||
"mathjs": "^15.2.0",
|
||||
"sharp": "~0.34.5",
|
||||
"sort-package-json": "^3.6.1",
|
||||
"stylelint": "^17.9.1",
|
||||
"stylelint": "^17.11.1",
|
||||
"stylelint-config-standard-less": "^4.1.0",
|
||||
"stylelint-prettier": "^5.0.3",
|
||||
"svgo": "^4.0.1",
|
||||
"typescript": "~6.0.3",
|
||||
"vite": "^8.0.10",
|
||||
"vite": "^8.0.13",
|
||||
"vite-bundle-analyzer": "^1.3.8"
|
||||
}
|
||||
},
|
||||
@@ -69,9 +69,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.13.tgz",
|
||||
"integrity": "sha512-gLXOwkOBBg0tr7bDsqlkIh4uFeKuMjxvqsrb1Tukww1iDmHcfr4Uu8MoQxp0Rcte+69+osRNWXwHsu/zxT6XqA==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz",
|
||||
"integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"bin": {
|
||||
@@ -85,20 +85,20 @@
|
||||
"url": "https://opencollective.com/biome"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@biomejs/cli-darwin-arm64": "2.4.13",
|
||||
"@biomejs/cli-darwin-x64": "2.4.13",
|
||||
"@biomejs/cli-linux-arm64": "2.4.13",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.4.13",
|
||||
"@biomejs/cli-linux-x64": "2.4.13",
|
||||
"@biomejs/cli-linux-x64-musl": "2.4.13",
|
||||
"@biomejs/cli-win32-arm64": "2.4.13",
|
||||
"@biomejs/cli-win32-x64": "2.4.13"
|
||||
"@biomejs/cli-darwin-arm64": "2.4.15",
|
||||
"@biomejs/cli-darwin-x64": "2.4.15",
|
||||
"@biomejs/cli-linux-arm64": "2.4.15",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.4.15",
|
||||
"@biomejs/cli-linux-x64": "2.4.15",
|
||||
"@biomejs/cli-linux-x64-musl": "2.4.15",
|
||||
"@biomejs/cli-win32-arm64": "2.4.15",
|
||||
"@biomejs/cli-win32-x64": "2.4.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.13.tgz",
|
||||
"integrity": "sha512-2KImO1jhNFBa2oWConyr0x6flxbQpGKv6902uGXpYM62Xyem8U80j441SyUJ8KyngsmKbQjeIv1q2CQfDkNnYg==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -113,9 +113,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-x64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.13.tgz",
|
||||
"integrity": "sha512-BKrJklbaFN4p1Ts4kPBczo+PkbsHQg57kmJ+vON9u2t6uN5okYHaSr7h/MutPCWQgg2lglaWoSmm+zhYW+oOkg==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -130,9 +130,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.13.tgz",
|
||||
"integrity": "sha512-NzkUDSqfvMBrPplKgVr3aXLHZ2NEELvvF4vZxXulEylKWIGqlvNEcwUcj9OLrn75TD3lJ/GIqCVlBwd1MZCuYQ==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -147,9 +147,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.13.tgz",
|
||||
"integrity": "sha512-U5MsuBQW25dXaYtqWWSPM3P96H6Y+fHuja3TQpMNnylocHW0tEbtFTDlUj6oM+YJLntvEkQy4grBvQNUD4+RCg==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz",
|
||||
"integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -164,9 +164,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.13.tgz",
|
||||
"integrity": "sha512-Az3ZZedYRBo9EQzNnD9SxFcR1G5QsGo6VEc2hIyVPZ1rdKwee/7E9oeBBZFpE8Z44ekxsDQBqbiWGW5ShOhUSQ==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -181,9 +181,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.13.tgz",
|
||||
"integrity": "sha512-Z601MienRgTBDza/+u2CH3RSrWoXo9rtr8NK6A4KJzqGgfxx+H3VlyLgTJ4sRo40T3pIsqpTmiOQEvYzQvBRvQ==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz",
|
||||
"integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -198,9 +198,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-arm64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.13.tgz",
|
||||
"integrity": "sha512-Px9PS2B5/Q183bUwy/5VHqp3J2lzdOCeVGzMpphYfl8oSa7VDCqenBdqWpy6DCy/en4Rbf/Y1RieZF6dJPcc9A==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz",
|
||||
"integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -215,9 +215,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-x64": {
|
||||
"version": "2.4.13",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.13.tgz",
|
||||
"integrity": "sha512-tTcMkXyBrmHi9BfrD2VNHs/5rYIUKETqsBlYOvSAABwBkJhSDVb5e7wPukftsQbO3WzQkXe6kaztC6WtUOXSoQ==",
|
||||
"version": "2.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz",
|
||||
"integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1023,9 +1023,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.127.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz",
|
||||
"integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==",
|
||||
"version": "0.130.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.130.0.tgz",
|
||||
"integrity": "sha512-ibD2usx9JRu7f5pu2tMKMI4cpA4NgXJQoYRP4pQ7Pxmn1l6k/53qWtQWZayhYy3X4QZkt90Ot+mJEaeXouio6Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -1107,9 +1107,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-fJI3I0r3C3Oj/zdBCpaCmBRZYf07xpaq4yCfDDoSFm+beWNzbIl26puW8RraUdugoJw/95zerNOn6jasAhzSmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1124,9 +1124,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-cKnAhWEsV7TPcA/5EAteDp6KcJZBQ2G+BqE7zayMMi7kMvwRsbv7WT9aOnn0WNl4SKEIf43vjS31iUPu80nzXg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1141,9 +1141,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.1.tgz",
|
||||
"integrity": "sha512-YKrVwQjIRBPo+5G/u03wGjbdy4q7pyzCe93DK9VJ7zkVmeg8LJ7GbgsiHWdR4xSoe4CAXRD7Bcjgbtr64bkXNg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1158,9 +1158,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.1.tgz",
|
||||
"integrity": "sha512-z/oBsREo46SsFqBwYtFe0kpJeBijAT48O/WXLI4suiCLBkr03RTtTJMCzSdDd2znlh8VJizL09XVkQgk8IZonw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1175,9 +1175,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.1.tgz",
|
||||
"integrity": "sha512-ik8q7GM11zxvYxFc2PeDcT6TBvhCQMaUxfph/M5l9sKuTs/Sjg3L+Byw0F7w0ZVLBZmx30P+gG0ECzzN+MFcmQ==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1192,9 +1192,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.1.tgz",
|
||||
"integrity": "sha512-QoSx2EkyrrdZ6kcyE8stqZ62t0Yra8Fs5ia9lOxJrh6TMQJK7gQKmscdTHf7pOXKREKrVwOtJcQG3qVSfc866A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1209,9 +1209,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.1.tgz",
|
||||
"integrity": "sha512-uwNwFpwKeNiZawfAWBgg0VIztPTV3ihhh1vV334h9ivnNLorxnQMU6Fz8wG1Zb4Qh9LC1/MkcyT3YlDXG3Rsgg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1226,9 +1226,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.1.tgz",
|
||||
"integrity": "sha512-zY1bul7OWr7DFBiJ++wofXvnr8B45ce3QsQUhKrIhXsygAh7bTkwyeM1bi1a2g5C/yC/N8TZyGDEoMfm/l9mpg==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1243,9 +1243,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.1.tgz",
|
||||
"integrity": "sha512-0frlsT/f4Ft6I7SMESTKnF3cZsdicQn1dCMkF/jT9wDLE+gGoiQfv1nmT9e+s7s/fekvvy6tZM2jHvI2tkbJDQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1260,9 +1260,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.1.tgz",
|
||||
"integrity": "sha512-XABVmGp9Tg0WspTVvwduTc4fpqy6JnAUrSQe6OuyqD/03nI7r0O9OWUkMIwFrjKAIqolvqoA4ZrJppgwE0Gxmw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1277,9 +1277,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.1.tgz",
|
||||
"integrity": "sha512-bV4fzswuzVcKD90o/VM6QqKxnxlDq0g2BISDLNVmxrnhpv1DDbyPhCIjYfvzYLV+MvkKKnQt2Q6AO86SEBULUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1294,9 +1294,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.1.tgz",
|
||||
"integrity": "sha512-/Mh0Zhq3OP7fVs0kcQHZP6lZEthMGTaSf8UBQYSFEZDWGXXlEC+nJ6EqenaK2t4LBXMe3A+K/G2BVXXdtOr4PQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1311,9 +1311,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.1.tgz",
|
||||
"integrity": "sha512-+1xc9X45l8ufsBAm6Gjvx2qDRIY9lTVt0cgWNcJ+1gdhXvkbxePA60yRTwSTuXL09CMhyJmjpV7E3NoyxbqFQQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
@@ -1330,9 +1330,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.1.tgz",
|
||||
"integrity": "sha512-1D+UqZdfnuR+Jy1GgMJwi85bD40H21uNmOPRWQhw4oRSuolZ/B5rixZ45DK2KXOTCvmVCecauWgEhbw8bI7tOw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1347,9 +1347,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.1.tgz",
|
||||
"integrity": "sha512-INAycaWuhlOK3wk4mRHGsdgwYWmd9cChdPdE9bwWmy6rn9VqVNYNFGhOdXrofXUxwHIncSiPNb8tNm8knDVIeQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1364,9 +1364,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -1511,9 +1511,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
||||
"version": "0.10.2",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
|
||||
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -1522,13 +1522,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz",
|
||||
"integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==",
|
||||
"version": "25.8.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.8.0.tgz",
|
||||
"integrity": "sha512-TCFSk8IZh+iLX1xtksoBVtdmgL+1IX0fC9BeU4QqFSuNdN/K+HUlhqOzEmSYYpZUVsLYcPqc9KX+60iDuninSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.19.0"
|
||||
"undici-types": ">=7.24.0 <7.24.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/pluralize": {
|
||||
@@ -2434,9 +2434,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
|
||||
"integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
|
||||
"integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2747,16 +2747,6 @@
|
||||
"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": {
|
||||
"version": "4.1.16",
|
||||
"resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
|
||||
@@ -3475,9 +3465,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.10",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz",
|
||||
"integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==",
|
||||
"version": "8.5.14",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
|
||||
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3741,14 +3731,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.0.0-rc.17",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz",
|
||||
"integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==",
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.1.tgz",
|
||||
"integrity": "sha512-X0KQHljNnEkWNqqiz9zJrGunh1B0HgOxLXvnFpCOcadzcy5qohZ3tqMEUg00vncoRovXuK3ZqCT9KnnKzoInFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.127.0",
|
||||
"@rolldown/pluginutils": "1.0.0-rc.17"
|
||||
"@oxc-project/types": "=0.130.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
@@ -3757,21 +3747,21 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-darwin-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.17",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.17",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17"
|
||||
"@rolldown/binding-android-arm64": "1.0.1",
|
||||
"@rolldown/binding-darwin-arm64": "1.0.1",
|
||||
"@rolldown/binding-darwin-x64": "1.0.1",
|
||||
"@rolldown/binding-freebsd-x64": "1.0.1",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.0.1",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.0.1",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.0.1",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.0.1",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.0.1",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.0.1",
|
||||
"@rolldown/binding-linux-x64-musl": "1.0.1",
|
||||
"@rolldown/binding-openharmony-arm64": "1.0.1",
|
||||
"@rolldown/binding-wasm32-wasi": "1.0.1",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.0.1",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
@@ -4010,9 +4000,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz",
|
||||
"integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==",
|
||||
"version": "8.2.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz",
|
||||
"integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4059,9 +4049,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/stylelint": {
|
||||
"version": "17.9.1",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.9.1.tgz",
|
||||
"integrity": "sha512-THTmnAPJTrg/JhkTWZlSyrO+HUYMx6ELthIHeMyD2WOKqXIJUFQv2Yxn91bvUrZdbBJaW2dUuQdPST2wcQ6C3g==",
|
||||
"version": "17.11.1",
|
||||
"resolved": "https://registry.npmjs.org/stylelint/-/stylelint-17.11.1.tgz",
|
||||
"integrity": "sha512-+smN/HqVTggUx3iuAzOi9fPh8SrH+cJWlZrYVldXoJ06orWBhZ4Ue/QEp64oei6pVrAh4w3tG+Y12Vw7MbCFRQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -4096,17 +4086,16 @@
|
||||
"html-tags": "^5.1.0",
|
||||
"ignore": "^7.0.5",
|
||||
"import-meta-resolve": "^4.2.0",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"mathml-tag-names": "^4.0.0",
|
||||
"meow": "^14.1.0",
|
||||
"micromatch": "^4.0.8",
|
||||
"normalize-path": "^3.0.0",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss": "^8.5.9",
|
||||
"postcss": "^8.5.14",
|
||||
"postcss-safe-parser": "^7.0.1",
|
||||
"postcss-selector-parser": "^7.1.1",
|
||||
"postcss-value-parser": "^4.2.0",
|
||||
"string-width": "^8.2.0",
|
||||
"string-width": "^8.2.1",
|
||||
"supports-hyperlinks": "^4.4.0",
|
||||
"svg-tags": "^1.0.0",
|
||||
"table": "^6.9.0",
|
||||
@@ -4478,9 +4467,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.19.2",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz",
|
||||
"integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==",
|
||||
"version": "7.24.6",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
|
||||
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -4545,16 +4534,16 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "8.0.10",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz",
|
||||
"integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==",
|
||||
"version": "8.0.13",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.13.tgz",
|
||||
"integrity": "sha512-MFtjBYgzmSxmgA4RAfjIyXWpGe1oALnjgUTzzV7QLx/TKxCzjtMH6Fd9/eVK+5Fg1qNoz5VAwsmMs/NofrmJvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
"postcss": "^8.5.10",
|
||||
"rolldown": "1.0.0-rc.17",
|
||||
"postcss": "^8.5.14",
|
||||
"rolldown": "1.0.1",
|
||||
"tinyglobby": "^0.2.16"
|
||||
},
|
||||
"bin": {
|
||||
@@ -4571,7 +4560,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@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",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "^4.0.0",
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
"swiped-events": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.4.13",
|
||||
"@types/node": "^25.6.0",
|
||||
"@biomejs/biome": "2.4.15",
|
||||
"@types/node": "^25.8.0",
|
||||
"browserslist": "^4.28.2",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
"edge.js": "^6.5.0",
|
||||
@@ -38,12 +38,12 @@
|
||||
"mathjs": "^15.2.0",
|
||||
"sharp": "~0.34.5",
|
||||
"sort-package-json": "^3.6.1",
|
||||
"stylelint": "^17.9.1",
|
||||
"stylelint": "^17.11.1",
|
||||
"stylelint-config-standard-less": "^4.1.0",
|
||||
"stylelint-prettier": "^5.0.3",
|
||||
"svgo": "^4.0.1",
|
||||
"typescript": "~6.0.3",
|
||||
"vite": "^8.0.10",
|
||||
"vite": "^8.0.13",
|
||||
"vite-bundle-analyzer": "^1.3.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
@import "mixins.less";
|
||||
@import "toolkit.less";
|
||||
@import "autocomplete.less";
|
||||
@import "detail.less";
|
||||
@import "animations.less";
|
||||
@import "embedded.less";
|
||||
@import "info.less";
|
||||
@@ -1165,3 +1164,4 @@ pre code {
|
||||
@import "result_types/code.less";
|
||||
@import "result_types/paper.less";
|
||||
@import "result_types/file.less";
|
||||
@import "result_types/image.less";
|
||||
|
||||
@@ -169,7 +169,7 @@ ${fedora_build}
|
||||
$ sudo -H -u ${SERVICE_USER} -i
|
||||
(${SERVICE_USER})$ cd ${SEARXNG_SRC}
|
||||
(${SERVICE_USER})$ export SEARXNG_SETTINGS_PATH=\"${SEARXNG_SETTINGS_PATH}\"
|
||||
(${SERVICE_USER})$ python searx/webapp.py
|
||||
(${SERVICE_USER})$ python -m searx.webapp
|
||||
|
||||
# disable debug
|
||||
$ sudo -H sed -i -e \"s/debug : True/debug : False/g\" \"$SEARXNG_SETTINGS_PATH\"
|
||||
|
||||
@@ -107,7 +107,7 @@ module:
|
||||
======================= =========== ===========================================
|
||||
base_url string base-url, can be overwritten to use same
|
||||
engine on other URL
|
||||
number_of_results int maximum number of results per request
|
||||
page_size int maximum number of results per request
|
||||
language string ISO code of language and country like en_US
|
||||
api_key string api-key if required by engine
|
||||
======================= =========== ===========================================
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
.. _500px engine:
|
||||
|
||||
=====
|
||||
500px
|
||||
=====
|
||||
|
||||
.. automodule:: searx.engines.500px
|
||||
:members:
|
||||
@@ -0,0 +1,8 @@
|
||||
.. _cara engine:
|
||||
|
||||
===========
|
||||
Cara Images
|
||||
===========
|
||||
|
||||
.. automodule:: searx.engines.cara
|
||||
:members:
|
||||
+19
-1
@@ -60,11 +60,29 @@ into the developer environment and start a python based HTTP server by::
|
||||
|
||||
$ ./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
|
||||
``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
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
.. _result_types.image:
|
||||
|
||||
=============
|
||||
Image Results
|
||||
=============
|
||||
|
||||
.. automodule:: searx.result_types.image
|
||||
@@ -1,4 +1,8 @@
|
||||
.. _result_types.mainresult:
|
||||
|
||||
============
|
||||
Main Results
|
||||
============
|
||||
|
||||
.. autoclass:: searx.result_types._base.MainResult
|
||||
:members:
|
||||
|
||||
@@ -18,13 +18,13 @@ following types have been implemented so far ..
|
||||
main/code
|
||||
main/paper
|
||||
main/file
|
||||
main/image
|
||||
|
||||
The :ref:`LegacyResult <LegacyResult>` is used internally for the results that
|
||||
have not yet been typed. The templates can be used as orientation until the
|
||||
final typing is complete.
|
||||
|
||||
- :ref:`template default` / :py:obj:`Result`
|
||||
- :ref:`template images`
|
||||
- :ref:`template videos`
|
||||
- :ref:`template torrent`
|
||||
- :ref:`template map`
|
||||
|
||||
@@ -129,53 +129,6 @@ audio_src : uri,
|
||||
URL of an embedded ``<audio controls>``.
|
||||
|
||||
|
||||
.. _template images:
|
||||
|
||||
``images.html``
|
||||
---------------
|
||||
|
||||
The images are displayed as small thumbnails in the main results list.
|
||||
|
||||
title : :py:class:`str`
|
||||
Title of the image.
|
||||
|
||||
thumbnail_src : :py:class:`str`
|
||||
URL of a preview of the image.
|
||||
|
||||
resolution :py:class:`str`
|
||||
The resolution of the image (e.g. ``1920 x 1080`` pixel)
|
||||
|
||||
|
||||
Image labels
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Clicking on the preview opens a gallery view in which all further metadata for
|
||||
the image is displayed. Addition fields used in the :origin:`images.html
|
||||
<searx/templates/simple/result_templates/images.html>`:
|
||||
|
||||
img_src : :py:class:`str`
|
||||
URL of the full size image.
|
||||
|
||||
content: :py:class:`str`
|
||||
Description of the image.
|
||||
|
||||
author: :py:class:`str`
|
||||
Name of the author of the image.
|
||||
|
||||
img_format : :py:class:`str`
|
||||
The format of the image (e.g. ``png``).
|
||||
|
||||
source : :py:class:`str`
|
||||
Source of the image.
|
||||
|
||||
filesize: :py:class:`str`
|
||||
Size of bytes in :py:obj:`human readable <searx.humanize_bytes>` notation
|
||||
(e.g. ``MB`` for 1024 \* 1024 Bytes filesize).
|
||||
|
||||
url : :py:class:`str`
|
||||
URL of the page from where the images comes from (source).
|
||||
|
||||
|
||||
.. _template videos:
|
||||
|
||||
``videos.html``
|
||||
|
||||
@@ -4,7 +4,7 @@ cov-core==1.15.0
|
||||
black==25.9.0
|
||||
pylint==4.0.5
|
||||
splinter==0.21.0
|
||||
selenium==4.43.0
|
||||
selenium==4.44.0
|
||||
Sphinx==8.2.3;python_version <= "3.11"
|
||||
Sphinx==9.1.0; python_version > "3.11"
|
||||
sphinx-issues==6.0.0
|
||||
@@ -23,6 +23,6 @@ coloredlogs==15.0.1
|
||||
docutils>=0.21.2;python_version <= "3.11"
|
||||
docutils>=0.22.4; python_version > "3.11"
|
||||
parameterized==0.9.0
|
||||
granian[reload]==2.7.4
|
||||
basedpyright==1.39.3
|
||||
granian[reload]==2.7.5
|
||||
basedpyright==1.39.6
|
||||
types-lxml==2026.2.16
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
granian==2.7.4
|
||||
granian[pname]==2.7.4
|
||||
granian==2.7.5
|
||||
granian[pname]==2.7.5
|
||||
|
||||
+4
-4
@@ -1,9 +1,9 @@
|
||||
certifi==2026.4.22
|
||||
certifi==2026.5.20
|
||||
babel==2.18.0
|
||||
flask-babel==4.0.0
|
||||
flask==3.1.3
|
||||
jinja2==3.1.6
|
||||
lxml==6.1.0
|
||||
lxml==6.1.1
|
||||
pygments==2.20.0
|
||||
python-dateutil==2.9.0.post0
|
||||
pyyaml==6.0.3
|
||||
@@ -11,9 +11,9 @@ httpx[http2]==0.28.1
|
||||
httpx-socks[asyncio]==0.10.0
|
||||
sniffio==1.3.1
|
||||
valkey==6.1.1
|
||||
markdown-it-py==4.0.0
|
||||
markdown-it-py==4.2.0
|
||||
msgspec==0.21.1
|
||||
typer==0.25.1
|
||||
typer==0.26.3
|
||||
isodate==0.7.2
|
||||
whitenoise==6.12.0
|
||||
typing-extensions==4.15.0
|
||||
|
||||
+7
-1
@@ -114,7 +114,13 @@ class ExpireCacheStats:
|
||||
if expire:
|
||||
valid_until = datetime.datetime.fromtimestamp(expire).strftime("%Y-%m-%d %H:%M:%S")
|
||||
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 key/value pairs: {c_kv}")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+61
-23
@@ -84,6 +84,7 @@
|
||||
"sr": "УАЕ дирхам",
|
||||
"sv": "Emiratisk dirham",
|
||||
"ta": "ஐக்கிய அரபு அமீரக திர்கம்",
|
||||
"te": "యూఏఈ దిర్హామ్",
|
||||
"tr": "Birleşik Arap Emirlikleri dirhemi",
|
||||
"tt": "БГӘ дирһәме",
|
||||
"uk": "дирхам ОАЕ"
|
||||
@@ -165,7 +166,7 @@
|
||||
"pap": "lek albanes",
|
||||
"pl": "lek",
|
||||
"pt": "lek",
|
||||
"ro": "Lek",
|
||||
"ro": "lek albanez",
|
||||
"ru": "албанский лек",
|
||||
"sk": "Albánsky lek",
|
||||
"sl": "albanski lek",
|
||||
@@ -738,6 +739,7 @@
|
||||
"sr": "брунејски долар",
|
||||
"sv": "Bruneisk dollar",
|
||||
"ta": "புரூணை டாலர்",
|
||||
"te": "బ్రూనై డాలర్",
|
||||
"th": "ดอลลาร์บรูไน",
|
||||
"tr": "Brunei doları",
|
||||
"tt": "Бруней доллары",
|
||||
@@ -911,6 +913,7 @@
|
||||
"sr": "бутански нгултрум",
|
||||
"sv": "Ngultrum",
|
||||
"ta": "பூட்டானின் இங்குல்ட்ரம்",
|
||||
"te": "భూటానీస్ గుల్త్రమ్",
|
||||
"th": "งุลตรัมภูฏาน",
|
||||
"tr": "Ngultrum",
|
||||
"tt": "ңгултрум",
|
||||
@@ -989,7 +992,7 @@
|
||||
"pa": "ਬੈਲਾਰੂਸੀ ਰੂਬਲ",
|
||||
"pl": "Rubel białoruski",
|
||||
"pt": "Rublo bielorrusso",
|
||||
"ro": "Rublă belarusă",
|
||||
"ro": "rublă belarusă",
|
||||
"ru": "Белорусский рубль",
|
||||
"sk": "Bieloruský rubeľ",
|
||||
"sl": "beloruski rubelj",
|
||||
@@ -1083,6 +1086,7 @@
|
||||
"sr": "канадски долар",
|
||||
"sv": "kanadensisk dollar",
|
||||
"ta": "கனடா டொலர்",
|
||||
"te": "కెనడియన్ డాలర్",
|
||||
"th": "ดอลลาร์แคนาดา",
|
||||
"tr": "Kanada doları",
|
||||
"tt": "Канада дуллыры",
|
||||
@@ -1231,6 +1235,7 @@
|
||||
"sl": "čilski peso",
|
||||
"sr": "чилеански пезос",
|
||||
"sv": "Chilensk peso",
|
||||
"te": "చిలీ పెసో",
|
||||
"th": "เปโซชิลี",
|
||||
"tr": "Şili pesosu",
|
||||
"tt": "Чили песосы",
|
||||
@@ -1284,6 +1289,7 @@
|
||||
"sr": "ренминби",
|
||||
"sv": "Renminbi",
|
||||
"ta": "ரென்மின்பி",
|
||||
"te": "రెన్మిన్బి",
|
||||
"th": "เหรินหมินปี้",
|
||||
"tr": "Renminbi",
|
||||
"tt": "юән",
|
||||
@@ -1702,7 +1708,7 @@
|
||||
"vi": "Bảng Ai Cập"
|
||||
},
|
||||
"ERN": {
|
||||
"ar": "ناكفا",
|
||||
"ar": "نقفة",
|
||||
"ca": "nakfa",
|
||||
"cs": "Eritrejská nakfa",
|
||||
"da": "Nakfa",
|
||||
@@ -1776,11 +1782,11 @@
|
||||
"bg": "евро",
|
||||
"bn": "ইউরো",
|
||||
"ca": "euro",
|
||||
"cs": "euro",
|
||||
"cs": "Euro",
|
||||
"cy": "Ewro",
|
||||
"da": "Euro",
|
||||
"de": "Euro",
|
||||
"en": "euro",
|
||||
"en": "Euro",
|
||||
"eo": "eŭro",
|
||||
"es": "Euro",
|
||||
"et": "Euro",
|
||||
@@ -1794,7 +1800,7 @@
|
||||
"hu": "euró",
|
||||
"ia": "Euro",
|
||||
"id": "Euro",
|
||||
"it": "euro",
|
||||
"it": "Euro",
|
||||
"ja": "ユーロ",
|
||||
"ko": "유로",
|
||||
"lt": "Euras",
|
||||
@@ -1805,11 +1811,11 @@
|
||||
"oc": "Èuro",
|
||||
"pa": "ਯੂਰੋ",
|
||||
"pap": "Euro",
|
||||
"pl": "euro",
|
||||
"pl": "Euro",
|
||||
"pt": "Euro",
|
||||
"ro": "euro",
|
||||
"ro": "Euro",
|
||||
"ru": "евро",
|
||||
"sk": "euro",
|
||||
"sk": "Euro",
|
||||
"sl": "evro",
|
||||
"sr": "евро",
|
||||
"sv": "Euro",
|
||||
@@ -1935,7 +1941,7 @@
|
||||
"sk": "libra šterlingov",
|
||||
"sl": "funt šterling",
|
||||
"sr": "британска фунта",
|
||||
"sv": "Brittiskt pund",
|
||||
"sv": "brittiskt pund",
|
||||
"ta": "பிரித்தானிய பவுண்டு",
|
||||
"th": "ปอนด์สเตอร์ลิง",
|
||||
"tr": "İngiliz sterlini",
|
||||
@@ -2410,6 +2416,7 @@
|
||||
"pl": "rupia indonezyjska",
|
||||
"pt": "rupia indonésia",
|
||||
"ru": "индонезийская рупия",
|
||||
"sk": "Indonézska rupia",
|
||||
"sl": "indonezijska rupija",
|
||||
"sr": "индонежанска рупија",
|
||||
"sv": "Rupiah",
|
||||
@@ -2463,6 +2470,7 @@
|
||||
"sr": "нови израелски шекел",
|
||||
"sv": "Shekel",
|
||||
"ta": "புது இசுரேலிய சேக்கல்",
|
||||
"te": "ఇజ్రాయెల్ షెకెల్",
|
||||
"tr": "Yeni İsrail Şekeli",
|
||||
"tt": "Исраил шекеле",
|
||||
"uk": "ізраїльський новий шекель"
|
||||
@@ -2758,6 +2766,7 @@
|
||||
"sr": "јапански јен",
|
||||
"sv": "yen",
|
||||
"ta": "யென்",
|
||||
"te": "జపనీస్ యెన్",
|
||||
"th": "เยน",
|
||||
"tr": "Japon yeni",
|
||||
"tt": "япон иенасы",
|
||||
@@ -2823,6 +2832,7 @@
|
||||
"ja": "キルギス・ソム",
|
||||
"ko": "키르기스스탄 솜",
|
||||
"lt": "somas",
|
||||
"lv": "Kirgizstānas soms",
|
||||
"nl": "Kirgizische som",
|
||||
"pa": "ਕਿਰਗਿਜ਼ਸਤਾਨੀ ਸੋਮ",
|
||||
"pl": "som",
|
||||
@@ -3236,6 +3246,7 @@
|
||||
"sr": "шриланчанска рупија",
|
||||
"sv": "Lankesisk rupie",
|
||||
"ta": "இலங்கை ரூபாய்",
|
||||
"te": "శ్రీలంక రూపాయి",
|
||||
"tr": "Sri Lanka rupisi",
|
||||
"tt": "Шри-Ланка рупиясе",
|
||||
"uk": "ланкійська рупія",
|
||||
@@ -3810,6 +3821,7 @@
|
||||
"MXV": {
|
||||
"de": "UNIDAD DE INVERSION",
|
||||
"en": "unidad de inversión",
|
||||
"eo": "Meksika unuo de investo",
|
||||
"es": "Unidades de Inversión",
|
||||
"ja": "メキシコ投資単位"
|
||||
},
|
||||
@@ -3901,7 +3913,7 @@
|
||||
"de": "Namibia-Dollar",
|
||||
"en": "Namibian dollar",
|
||||
"eo": "namibia dolaro",
|
||||
"es": "Dólar namibio",
|
||||
"es": "dólar namibio",
|
||||
"fi": "Namibian dollari",
|
||||
"fr": "Dollar namibien",
|
||||
"ga": "dollar na Namaibe",
|
||||
@@ -4090,6 +4102,7 @@
|
||||
"sr": "непалска рупија",
|
||||
"sv": "Nepalesisk rupee",
|
||||
"ta": "நேபாள ரூபாய்",
|
||||
"te": "నేపాలీ రూపాయి",
|
||||
"th": "รูปีเนปาล",
|
||||
"tr": "Nepal rupisi",
|
||||
"tt": "Непал рупиясе",
|
||||
@@ -4325,6 +4338,7 @@
|
||||
"sr": "филипински пезо",
|
||||
"sv": "Filippinsk peso",
|
||||
"ta": "பிலிப்பைன் பெசோ",
|
||||
"te": "ఫిలిప్పీన్ పెసో",
|
||||
"th": "เปโซฟิลิปปินส์",
|
||||
"tr": "Filipinler pesosu",
|
||||
"tt": "Филипин писысы",
|
||||
@@ -4370,6 +4384,7 @@
|
||||
"sr": "пакистанска рупија",
|
||||
"sv": "Pakistansk rupee",
|
||||
"ta": "பாக்கித்தானிய ரூபாய்",
|
||||
"te": "పాకిస్థానీ రూపాయి",
|
||||
"tr": "Pakistan rupisi",
|
||||
"tt": "Пакстан рупиясе",
|
||||
"uk": "пакистанська рупія",
|
||||
@@ -4549,7 +4564,7 @@
|
||||
"de": "rumänischer Leu",
|
||||
"en": "Romanian Leu",
|
||||
"eo": "rumana leo",
|
||||
"es": "Leu rumano",
|
||||
"es": "leu rumano",
|
||||
"et": "Rumeenia leu",
|
||||
"fi": "Romanian leu",
|
||||
"fr": "leu roumain",
|
||||
@@ -4750,6 +4765,7 @@
|
||||
"sr": "саудијски ријал",
|
||||
"sv": "Saudiarabisk rial",
|
||||
"ta": "சவூதி ரியால்",
|
||||
"te": "సౌదీ రియాల్",
|
||||
"tr": "Suudi Arabistan riyali",
|
||||
"tt": "Согуд риялы",
|
||||
"uk": "саудівський ріал",
|
||||
@@ -4948,6 +4964,7 @@
|
||||
"sr": "сингапурски долар",
|
||||
"sv": "Singaporiansk dollar",
|
||||
"ta": "சிங்கப்பூர் வெள்ளி",
|
||||
"te": "సింగపూర్ డాలర్",
|
||||
"th": "ดอลลาร์สิงคโปร์",
|
||||
"tr": "Singapur doları",
|
||||
"tt": "Сингапур доллары",
|
||||
@@ -5175,7 +5192,7 @@
|
||||
"de": "syrische Lira",
|
||||
"en": "Syrian pound",
|
||||
"eo": "siria pundo",
|
||||
"es": "Dolar sirio",
|
||||
"es": "libra siria",
|
||||
"fi": "Syyrian punta",
|
||||
"fr": "livre syrienne",
|
||||
"ga": "punt na Siria",
|
||||
@@ -5977,7 +5994,7 @@
|
||||
"ms": "Franc CFA Afrika Tengah",
|
||||
"nl": "Central African CFA franc",
|
||||
"oc": "Franc CFA d'Africa Centrala",
|
||||
"pl": "środkowoafrykański frank CFA",
|
||||
"pl": "frank CFA",
|
||||
"pt": "franco",
|
||||
"ro": "Franc CFA BEAC",
|
||||
"ru": "франк КФА BEAC",
|
||||
@@ -5999,6 +6016,7 @@
|
||||
"fr": "argent d'investissement",
|
||||
"ja": "投資対象としての銀",
|
||||
"ms": "Perak sebagai pelaburan",
|
||||
"pt": "Prata como investimento",
|
||||
"ru": "серебро как инвестиция",
|
||||
"sv": "Silver som investering",
|
||||
"tr": "Yatırım olarak gümüş",
|
||||
@@ -6017,6 +6035,7 @@
|
||||
"lv": "zelts kā investīcija",
|
||||
"ml": "സ്വർണവും സാമ്പത്തിക ശാസ്ത്രവും",
|
||||
"ms": "emas sebagai pelaburan",
|
||||
"pt": "Ouro como investimento",
|
||||
"ru": "золото как инвестиция",
|
||||
"sr": "investiciono zlato",
|
||||
"sv": "investeringsguld",
|
||||
@@ -7905,7 +7924,6 @@
|
||||
"dolar de las islas caimán": "KYD",
|
||||
"dolar de las islas salomon": "SBD",
|
||||
"dolar de las islas salomón": "SBD",
|
||||
"dolar de namibia": "NAD",
|
||||
"dolar de nueva zelanda": "NZD",
|
||||
"dolar de singapor": "SGD",
|
||||
"dolar de singapur": "SGD",
|
||||
@@ -7963,7 +7981,6 @@
|
||||
"dolar namibia": "NAD",
|
||||
"dolar namibian": "NAD",
|
||||
"dolar namibijski": "NAD",
|
||||
"dolar namibio": "NAD",
|
||||
"dolar neocelandes": "NZD",
|
||||
"dolar neocelandés": "NZD",
|
||||
"dolar neozeelandez": "NZD",
|
||||
@@ -7978,7 +7995,6 @@
|
||||
"dolar singapura": "SGD",
|
||||
"dolar singapurski": "SGD",
|
||||
"dolar singapurtar": "SGD",
|
||||
"dolar sirio": "SYP",
|
||||
"dolar sua": "USD",
|
||||
"dolar surinamdar": "SRD",
|
||||
"dolar suriname": "SRD",
|
||||
@@ -8179,6 +8195,7 @@
|
||||
"dominicaanse peso": "DOP",
|
||||
"dominican peso": "DOP",
|
||||
"dominican peso oro": "DOP",
|
||||
"dominički pezo": "DOP",
|
||||
"dominik pesosu": "DOP",
|
||||
"dominika peso": "DOP",
|
||||
"dominikaanisen tasavallan peso": "DOP",
|
||||
@@ -8528,7 +8545,6 @@
|
||||
"etiópsky birr": "ETB",
|
||||
"eua 17": "XBD",
|
||||
"eua 9": "XBC",
|
||||
"eur": "EUR",
|
||||
"euras": "EUR",
|
||||
"eurco": "XBA",
|
||||
"euro": "EUR",
|
||||
@@ -8859,7 +8875,6 @@
|
||||
"frank kongijski": "CDF",
|
||||
"frank rwandyjski": "RWF",
|
||||
"frank szwajcarski": "CHF",
|
||||
"frank zachodnioafrykański": "XOF",
|
||||
"franko suitzar": "CHF",
|
||||
"frw": "RWF",
|
||||
"ft": "HUF",
|
||||
@@ -9180,6 +9195,7 @@
|
||||
"indonezijska rupija": "IDR",
|
||||
"indonéská rupie": "IDR",
|
||||
"indonéz rúpia": "IDR",
|
||||
"indonézska rupia": "IDR",
|
||||
"indonēziešu rūpija": "IDR",
|
||||
"indonēzijas rūpija": "IDR",
|
||||
"inglise nael": "GBP",
|
||||
@@ -9494,6 +9510,8 @@
|
||||
"kirgizia somo": "KGS",
|
||||
"kirgizische som": "KGS",
|
||||
"kirgizistansk som": "KGS",
|
||||
"kirgizstānas soms": "KGS",
|
||||
"kirgīzu soms": "KGS",
|
||||
"kiwi dollar": "NZD",
|
||||
"kínai jüan": "CNY",
|
||||
"kíp": "LAK",
|
||||
@@ -9810,7 +9828,6 @@
|
||||
"lek na halbáine": "ALL",
|
||||
"lek novo": "ALL",
|
||||
"lekas": "ALL",
|
||||
"lekă albaneză": "ALL",
|
||||
"lekë": "ALL",
|
||||
"leko": "ALL",
|
||||
"lempira": "HNL",
|
||||
@@ -9981,6 +9998,7 @@
|
||||
"lira libanesa": "LBP",
|
||||
"lira libanese": "LBP",
|
||||
"lira na tuirce": "TRY",
|
||||
"lira siria": "SYP",
|
||||
"lira siriana": "SYP",
|
||||
"lira síria": "SYP",
|
||||
"lira thổ nhĩ kỳ": "TRY",
|
||||
@@ -10291,6 +10309,7 @@
|
||||
"meksički pezo": "MXN",
|
||||
"meksika peso": "MXN",
|
||||
"meksika pesosu": "MXN",
|
||||
"meksika unuo de investo": "MXV",
|
||||
"meksikaanse peso": "MXN",
|
||||
"meksikas peso": "MXN",
|
||||
"meksikon peso": "MXN",
|
||||
@@ -10746,6 +10765,7 @@
|
||||
"ouguiya mauritanien": "MRU",
|
||||
"ouguiya mawritania": "MRU",
|
||||
"ouguiya na máratáine": "MRU",
|
||||
"ouro como investimento": "XAU",
|
||||
"ouro do zimbábue": "ZWG",
|
||||
"örmény dram": "AMD",
|
||||
"östkaribisk dollar": "XCD",
|
||||
@@ -11111,6 +11131,7 @@
|
||||
"põhja korea vonn": "KPW",
|
||||
"põhja korea won": "KPW",
|
||||
"põhja makedoonia denaar": "MKD",
|
||||
"prata como investimento": "XAG",
|
||||
"pula": "BWP",
|
||||
"pula botswana": "BWP",
|
||||
"pula botswanais": "BWP",
|
||||
@@ -11901,6 +11922,7 @@
|
||||
"somoni taxico": "TJS",
|
||||
"somoni tayiko": "TJS",
|
||||
"somonis": "TJS",
|
||||
"soms": "KGS",
|
||||
"sonderziehungsrecht": "XDR",
|
||||
"sos": "SOS",
|
||||
"sosh": "SOS",
|
||||
@@ -12102,7 +12124,6 @@
|
||||
"szyling tanzański": "TZS",
|
||||
"szyling ugandyjski": "UGX",
|
||||
"sırp dinarı": "RSD",
|
||||
"środkowoafrykański frank cfa": "XAF",
|
||||
"šalamounský dolar": "SBD",
|
||||
"šalomounský dolar": "SBD",
|
||||
"šekel chadaš": "ILS",
|
||||
@@ -14017,6 +14038,7 @@
|
||||
"самоанский доллар": "WST",
|
||||
"самоанська тала": "WST",
|
||||
"сан томе һәм принсипи добрасы": "STN",
|
||||
"саотомеанска добра": "STN",
|
||||
"саотомска добра": "STN",
|
||||
"саудитски риал": "SAR",
|
||||
"саудијски риал": "SAR",
|
||||
@@ -15350,13 +15372,28 @@
|
||||
"ஹங்கேரிய போரிண்ட்": "HUF",
|
||||
"ஹிருன்யா": "UAH",
|
||||
"ஹொங்கொங் டொலர்": "HKD",
|
||||
"అమెరికన్ డాలర్": "USD",
|
||||
"ఇజ్రాయెల్ షెకెల్": "ILS",
|
||||
"కెనడియన్ డాలర్": "CAD",
|
||||
"చిలీ పెసో": "CLP",
|
||||
"జపనీస్ యెన్": "JPY",
|
||||
"డిజిటల్ రూపాయి": "INR",
|
||||
"నేపాలీ రూపాయి": "NPR",
|
||||
"పాకిస్థానీ రూపాయి": "PKR",
|
||||
"ఫిలిప్పీన్ పెసో": "PHP",
|
||||
"బ్రూనై డాలర్": "BND",
|
||||
"భారత రూపాయి": "INR",
|
||||
"భారతదేశ రూపాయి": "INR",
|
||||
"భారతీయ రూపాయి": "INR",
|
||||
"భూటానీస్ గుల్త్రమ్": "BTN",
|
||||
"యునైటెడ్ స్టేట్స్ డాలర్": "USD",
|
||||
"యూఏఈ దిర్హామ్": "AED",
|
||||
"యూరో": "EUR",
|
||||
"రూపాయి": "INR",
|
||||
"రెన్మిన్బి": "CNY",
|
||||
"శ్రీలంక రూపాయి": "LKR",
|
||||
"సింగపూర్ డాలర్": "SGD",
|
||||
"సౌదీ రియాల్": "SAR",
|
||||
"స్విస్ ఫ్రాంక్": "CHF",
|
||||
"അൾജീരിയൻ ദിനാർ": "DZD",
|
||||
"ഇന്തോനേഷ്യൻ റുപിയ": "IDR",
|
||||
@@ -15607,6 +15644,8 @@
|
||||
"부탄 뉘땀": "BTN",
|
||||
"부탄눌트럼": "BTN",
|
||||
"북마케도니아 데나르": "MKD",
|
||||
"북조선 원": "KPW",
|
||||
"북한 원": "KPW",
|
||||
"브라질 레알": "BRL",
|
||||
"브라질 헤알": "BRL",
|
||||
"브루나이 달러": "BND",
|
||||
@@ -16199,7 +16238,6 @@
|
||||
"香港・ドル": "HKD",
|
||||
"香港元": "HKD",
|
||||
"﷼": "IRR",
|
||||
"﷼'": "YER",
|
||||
"💶": "EUR"
|
||||
"﷼'": "YER"
|
||||
}
|
||||
}
|
||||
+364
-585
File diff suppressed because it is too large
Load Diff
@@ -4079,6 +4079,7 @@
|
||||
"bg-BG": "BG:bg",
|
||||
"bn-BD": "BD:bn",
|
||||
"bn-IN": "IN:bn",
|
||||
"ca-ES": "ES:ca",
|
||||
"cs-CZ": "CZ:cs",
|
||||
"de-AT": "AT:de",
|
||||
"de-CH": "CH:de",
|
||||
@@ -4110,16 +4111,15 @@
|
||||
"es-CO": "CO:es-419",
|
||||
"es-CU": "CU:es-419",
|
||||
"es-ES": "ES:es",
|
||||
"es-MX": "MX:es-419",
|
||||
"es-PE": "PE:es-419",
|
||||
"es-US": "US:es-419",
|
||||
"es-VE": "VE:es-419",
|
||||
"et-EE": "EE:et",
|
||||
"fi-FI": "FI:fi",
|
||||
"fr-BE": "BE:fr",
|
||||
"fr-CA": "CA:fr",
|
||||
"fr-CH": "CH:fr",
|
||||
"fr-FR": "FR:fr",
|
||||
"fr-MA": "MA:fr",
|
||||
"fr-SN": "SN:fr",
|
||||
"gu-IN": "IN:gu",
|
||||
"he-IL": "IL:he",
|
||||
"hi-IN": "IN:hi",
|
||||
"hu-HU": "HU:hu",
|
||||
@@ -4131,12 +4131,13 @@
|
||||
"lv-LV": "LV:lv",
|
||||
"ml-IN": "IN:ml",
|
||||
"mr-IN": "IN:mr",
|
||||
"ms-MY": "MY:ms",
|
||||
"nb-NO": "NO:no",
|
||||
"nl-BE": "BE:nl",
|
||||
"nl-NL": "NL:nl",
|
||||
"pa-IN": "IN:pa",
|
||||
"pl-PL": "PL:pl",
|
||||
"pt-BR": "BR:pt-419",
|
||||
"pt-PT": "PT:pt-150",
|
||||
"ro-RO": "RO:ro",
|
||||
"ru-RU": "RU:ru",
|
||||
"ru-UA": "UA:ru",
|
||||
@@ -4151,8 +4152,7 @@
|
||||
"uk-UA": "UA:uk",
|
||||
"vi-VN": "VN:vi",
|
||||
"zh-CN": "CN:zh-Hans",
|
||||
"zh-HK": "HK:zh-Hant",
|
||||
"zh-TW": "TW:zh-Hant"
|
||||
"zh-HK": "HK:zh-Hant"
|
||||
},
|
||||
"supported_domains": {}
|
||||
},
|
||||
@@ -8513,6 +8513,177 @@
|
||||
"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": {
|
||||
"all_locale": "",
|
||||
"custom": {
|
||||
|
||||
+4502
-2286
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
],
|
||||
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
|
||||
"versions": [
|
||||
"150.0",
|
||||
"149.0"
|
||||
"151.0",
|
||||
"150.0"
|
||||
]
|
||||
}
|
||||
+258
-143
@@ -69,11 +69,6 @@
|
||||
"symbol": "pk (US)",
|
||||
"to_si_factor": 0.008809768
|
||||
},
|
||||
"Q101427917": {
|
||||
"si_name": "Q25517",
|
||||
"symbol": "pk (UK)",
|
||||
"to_si_factor": 0.00909218
|
||||
},
|
||||
"Q101428098": {
|
||||
"si_name": "Q44395",
|
||||
"symbol": "dbar",
|
||||
@@ -84,6 +79,11 @@
|
||||
"symbol": "μbar",
|
||||
"to_si_factor": 0.1
|
||||
},
|
||||
"Q101435213": {
|
||||
"si_name": "Q101435195",
|
||||
"symbol": "Jy s",
|
||||
"to_si_factor": 1e-26
|
||||
},
|
||||
"Q101435332": {
|
||||
"si_name": "Q44395",
|
||||
"symbol": "cm Hg",
|
||||
@@ -124,11 +124,6 @@
|
||||
"symbol": "pm²",
|
||||
"to_si_factor": 1e-24
|
||||
},
|
||||
"Q101463679": {
|
||||
"si_name": "Q25343",
|
||||
"symbol": "hm²",
|
||||
"to_si_factor": 10000.0
|
||||
},
|
||||
"Q101464050": {
|
||||
"si_name": "Q25343",
|
||||
"symbol": "Mm²",
|
||||
@@ -199,6 +194,11 @@
|
||||
"symbol": "d⁻¹",
|
||||
"to_si_factor": 1.15741e-05
|
||||
},
|
||||
"Q102129764": {
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "a⁻¹",
|
||||
"to_si_factor": 3.17098e-08
|
||||
},
|
||||
"Q102130673": {
|
||||
"si_name": "Q182429",
|
||||
"symbol": "ym/s",
|
||||
@@ -425,9 +425,9 @@
|
||||
"to_si_factor": 10.0
|
||||
},
|
||||
"Q1042866": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Zib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.1805916207174113e+21
|
||||
},
|
||||
"Q104317437": {
|
||||
"si_name": "Q25381181",
|
||||
@@ -995,9 +995,9 @@
|
||||
"to_si_factor": 1000000000000.0
|
||||
},
|
||||
"Q106247880": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "digit/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q106247940": {
|
||||
"si_name": null,
|
||||
@@ -1504,6 +1504,11 @@
|
||||
"symbol": "m²/(s² K)",
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q106707206": {
|
||||
"si_name": null,
|
||||
"symbol": "HU",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q106707404": {
|
||||
"si_name": "Q106707404",
|
||||
"symbol": "kg m²/(s² K)",
|
||||
@@ -2314,79 +2319,124 @@
|
||||
"symbol": "cm²/(sr erg)",
|
||||
"to_si_factor": 1000.0
|
||||
},
|
||||
"Q107710161": {
|
||||
"si_name": "Q199",
|
||||
"symbol": "J/bit",
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q107821494": {
|
||||
"si_name": null,
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "bit/m³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q107822428": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "bit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q107824325": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "bit/m²",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q107825143": {
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Eibit/m",
|
||||
"to_si_factor": 1.152921504606847e+18
|
||||
},
|
||||
"Q107825584": {
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Eibit/m²",
|
||||
"to_si_factor": 1.152921504606847e+18
|
||||
},
|
||||
"Q107825716": {
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Eibit/m³",
|
||||
"to_si_factor": 1.152921504606847e+18
|
||||
},
|
||||
"Q107862736": {
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Gibit/m",
|
||||
"to_si_factor": 1073741824.0
|
||||
},
|
||||
"Q107862746": {
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Gibit/m²",
|
||||
"to_si_factor": 1073741824.0
|
||||
},
|
||||
"Q107862762": {
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Gibit/m³",
|
||||
"to_si_factor": 1073741824.0
|
||||
},
|
||||
"Q107862770": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Kibit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1024.0
|
||||
},
|
||||
"Q107862783": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Kibit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1024.0
|
||||
},
|
||||
"Q107862850": {
|
||||
"si_name": null,
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Kibit/m³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1024.0
|
||||
},
|
||||
"Q107862870": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Mibit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1048576.0
|
||||
},
|
||||
"Q107862884": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Mibit/m²",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1048576.0
|
||||
},
|
||||
"Q107862898": {
|
||||
"si_name": null,
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Mibit/m³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1048576.0
|
||||
},
|
||||
"Q107970215": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Pibit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1125899906842624.0
|
||||
},
|
||||
"Q107970224": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Pibit/m²",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1125899906842624.0
|
||||
},
|
||||
"Q107970230": {
|
||||
"si_name": null,
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Pibit/m³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1125899906842624.0
|
||||
},
|
||||
"Q107970235": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547251",
|
||||
"symbol": "Tibit/m",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1099511627776.0
|
||||
},
|
||||
"Q107970256": {
|
||||
"si_name": null,
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "Tibit/m³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1099511627776.0
|
||||
},
|
||||
"Q107970266": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11547252",
|
||||
"symbol": "Tibit/m²",
|
||||
"to_si_factor": 1099511627776.0
|
||||
},
|
||||
"Q108112819": {
|
||||
"si_name": null,
|
||||
"symbol": "€/kWh",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q108112891": {
|
||||
"si_name": null,
|
||||
"symbol": "€/(MW h)",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q108270163": {
|
||||
@@ -2395,9 +2445,9 @@
|
||||
"to_si_factor": 3.169e-05
|
||||
},
|
||||
"Q1084321": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "Tb/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000000.0
|
||||
},
|
||||
"Q108533173": {
|
||||
"si_name": "Q108533173",
|
||||
@@ -2434,6 +2484,16 @@
|
||||
"symbol": "GeV/c²",
|
||||
"to_si_factor": 1.7826619216278976e-27
|
||||
},
|
||||
"Q108913970": {
|
||||
"si_name": null,
|
||||
"symbol": "person/km²",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q108914485": {
|
||||
"si_name": null,
|
||||
"symbol": "person/m²",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q108920356": {
|
||||
"si_name": "Q25406",
|
||||
"symbol": "esu",
|
||||
@@ -2464,6 +2524,11 @@
|
||||
"symbol": "e.u.",
|
||||
"to_si_factor": 4.184
|
||||
},
|
||||
"Q109337616": {
|
||||
"si_name": "Q139710667",
|
||||
"symbol": "1/(100 eV)",
|
||||
"to_si_factor": 6.2415e+16
|
||||
},
|
||||
"Q109448508": {
|
||||
"si_name": null,
|
||||
"symbol": "man-Sv",
|
||||
@@ -2499,6 +2564,11 @@
|
||||
"symbol": "nm²",
|
||||
"to_si_factor": 1e-18
|
||||
},
|
||||
"Q11123": {
|
||||
"si_name": "Q25517",
|
||||
"symbol": "pt (UK)",
|
||||
"to_si_factor": 0.00056826125
|
||||
},
|
||||
"Q111494193": {
|
||||
"si_name": "Q111494193",
|
||||
"symbol": "J/(Hz mol)",
|
||||
@@ -2509,6 +2579,11 @@
|
||||
"symbol": "%",
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q112659472": {
|
||||
"si_name": null,
|
||||
"symbol": "PVU",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q1131660": {
|
||||
"si_name": "Q11570",
|
||||
"symbol": "st",
|
||||
@@ -2540,14 +2615,14 @@
|
||||
"to_si_factor": 31688087.81402895
|
||||
},
|
||||
"Q1140444": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Zb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1e+21
|
||||
},
|
||||
"Q1140577": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Yb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.0
|
||||
},
|
||||
"Q114559346": {
|
||||
"si_name": null,
|
||||
@@ -2560,14 +2635,14 @@
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q1152074": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Pb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000000000.0
|
||||
},
|
||||
"Q1152323": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Tb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000000.0
|
||||
},
|
||||
"Q115277430": {
|
||||
"si_name": null,
|
||||
@@ -2810,14 +2885,14 @@
|
||||
"to_si_factor": 4.4482216152605
|
||||
},
|
||||
"Q1194580": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Mib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1048576.0
|
||||
},
|
||||
"Q1195111": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Eb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1e+18
|
||||
},
|
||||
"Q1196837": {
|
||||
"si_name": "Q1063756",
|
||||
@@ -2865,15 +2940,20 @@
|
||||
"to_si_factor": 0.03110348
|
||||
},
|
||||
"Q1204894": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Gib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1073741824.0
|
||||
},
|
||||
"Q12129": {
|
||||
"si_name": "Q11573",
|
||||
"symbol": "pc",
|
||||
"to_si_factor": 3.085677581491367e+16
|
||||
},
|
||||
"Q12145303": {
|
||||
"si_name": "Q11573",
|
||||
"symbol": "rd",
|
||||
"to_si_factor": 5.02921
|
||||
},
|
||||
"Q121965382": {
|
||||
"si_name": "Q121965382",
|
||||
"symbol": "mol/mol",
|
||||
@@ -3114,6 +3194,11 @@
|
||||
"symbol": "QF",
|
||||
"to_si_factor": 1e+30
|
||||
},
|
||||
"Q12558489": {
|
||||
"si_name": "Q25517",
|
||||
"symbol": "pk (UK)",
|
||||
"to_si_factor": 0.00909218
|
||||
},
|
||||
"Q125962250": {
|
||||
"si_name": null,
|
||||
"symbol": "Ry",
|
||||
@@ -3240,14 +3325,14 @@
|
||||
"to_si_factor": 1e-30
|
||||
},
|
||||
"Q131395783": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Rib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.2379400392853803e+27
|
||||
},
|
||||
"Q131395793": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Qib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.2676506002282294e+30
|
||||
},
|
||||
"Q13147228": {
|
||||
"si_name": "Q844211",
|
||||
@@ -3309,6 +3394,11 @@
|
||||
"symbol": "1/K",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q133796439": {
|
||||
"si_name": null,
|
||||
"symbol": "T/mm²",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q13400897": {
|
||||
"si_name": "Q1051665",
|
||||
"symbol": "g",
|
||||
@@ -3317,18 +3407,23 @@
|
||||
"Q13479685": {
|
||||
"si_name": "Q44395",
|
||||
"symbol": "mm H2O",
|
||||
"to_si_factor": 9.80638
|
||||
"to_si_factor": 9.80665
|
||||
},
|
||||
"Q1351253": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Eib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.152921504606847e+18
|
||||
},
|
||||
"Q1351334": {
|
||||
"si_name": null,
|
||||
"symbol": "Pib",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q135373020": {
|
||||
"si_name": null,
|
||||
"symbol": "GTexel",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q135415097": {
|
||||
"si_name": "Q25236",
|
||||
"symbol": "shp",
|
||||
@@ -3380,9 +3475,9 @@
|
||||
"to_si_factor": 1e-06
|
||||
},
|
||||
"Q136039973": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "FPS",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q1361854": {
|
||||
"si_name": "Q11570",
|
||||
@@ -3450,9 +3545,9 @@
|
||||
"to_si_factor": 1000000000000.0
|
||||
},
|
||||
"Q139054848": {
|
||||
"si_name": null,
|
||||
"si_name": "Q117899185",
|
||||
"symbol": "A·h/m²",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 3600.0
|
||||
},
|
||||
"Q139086088": {
|
||||
"si_name": "Q69425409",
|
||||
@@ -3642,7 +3737,7 @@
|
||||
"Q1654435": {
|
||||
"si_name": "Q25250",
|
||||
"symbol": "IRE",
|
||||
"to_si_factor": 0.007
|
||||
"to_si_factor": 0.007143
|
||||
},
|
||||
"Q16673974": {
|
||||
"si_name": null,
|
||||
@@ -3820,9 +3915,9 @@
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q18434272": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "°Balling",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q185078": {
|
||||
"si_name": "Q25343",
|
||||
@@ -3850,9 +3945,9 @@
|
||||
"to_si_factor": 1e-21
|
||||
},
|
||||
"Q188768": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "FLOPS",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q190095": {
|
||||
"si_name": "Q190095",
|
||||
@@ -3989,6 +4084,11 @@
|
||||
"symbol": "ppb",
|
||||
"to_si_factor": 1e-09
|
||||
},
|
||||
"Q206037": {
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "r/min",
|
||||
"to_si_factor": 0.0166667
|
||||
},
|
||||
"Q2064166": {
|
||||
"si_name": "Q179836",
|
||||
"symbol": "fc",
|
||||
@@ -4320,9 +4420,9 @@
|
||||
"to_si_factor": 10.0
|
||||
},
|
||||
"Q2243141": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "Gb/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000.0
|
||||
},
|
||||
"Q2254856": {
|
||||
"si_name": "Q25343",
|
||||
@@ -4335,9 +4435,9 @@
|
||||
"to_si_factor": 0.00508
|
||||
},
|
||||
"Q2269250": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "kb/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000.0
|
||||
},
|
||||
"Q2278977": {
|
||||
"si_name": null,
|
||||
@@ -4535,9 +4635,9 @@
|
||||
"to_si_factor": 898755178700.0
|
||||
},
|
||||
"Q25325238": {
|
||||
"si_name": null,
|
||||
"si_name": "Q106919394",
|
||||
"symbol": "bhp/cm³",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 745700000.0
|
||||
},
|
||||
"Q253276": {
|
||||
"si_name": "Q11573",
|
||||
@@ -4545,9 +4645,9 @@
|
||||
"to_si_factor": 1609.344
|
||||
},
|
||||
"Q2533495": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "°P",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q25343": {
|
||||
"si_name": "Q25343",
|
||||
@@ -4885,9 +4985,9 @@
|
||||
"to_si_factor": 9.80665
|
||||
},
|
||||
"Q28657331": {
|
||||
"si_name": null,
|
||||
"si_name": "Q106688958",
|
||||
"symbol": "erg/(s cm²)",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.001
|
||||
},
|
||||
"Q28683485": {
|
||||
"si_name": "Q28683485",
|
||||
@@ -4920,9 +5020,9 @@
|
||||
"to_si_factor": 0.001
|
||||
},
|
||||
"Q29463526": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "hr/yr",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.14155e-06
|
||||
},
|
||||
"Q296936": {
|
||||
"si_name": "Q25269",
|
||||
@@ -5155,9 +5255,9 @@
|
||||
"to_si_factor": 1e-15
|
||||
},
|
||||
"Q3194304": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "kb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000.0
|
||||
},
|
||||
"Q3196665": {
|
||||
"si_name": "Q215571",
|
||||
@@ -5295,9 +5395,9 @@
|
||||
"to_si_factor": 3517.0
|
||||
},
|
||||
"Q3332814": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Mb",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000.0
|
||||
},
|
||||
"Q33680": {
|
||||
"si_name": "Q33680",
|
||||
@@ -5390,9 +5490,9 @@
|
||||
"to_si_factor": 3.085677581e+22
|
||||
},
|
||||
"Q3815076": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Kib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1024.0
|
||||
},
|
||||
"Q3858002": {
|
||||
"si_name": "Q25406",
|
||||
@@ -5410,9 +5510,9 @@
|
||||
"to_si_factor": 0.3048
|
||||
},
|
||||
"Q389062": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Tib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1099511627776.0
|
||||
},
|
||||
"Q3902688": {
|
||||
"si_name": "Q25517",
|
||||
@@ -5534,6 +5634,11 @@
|
||||
"symbol": "D",
|
||||
"to_si_factor": 3.335640951981521e-30
|
||||
},
|
||||
"Q4063874": {
|
||||
"si_name": "Q21401573",
|
||||
"symbol": "amg",
|
||||
"to_si_factor": 2.6868e+25
|
||||
},
|
||||
"Q4068266": {
|
||||
"si_name": "Q11570",
|
||||
"symbol": "Ʒ",
|
||||
@@ -5640,9 +5745,9 @@
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q474533": {
|
||||
"si_name": null,
|
||||
"si_name": "Q25272",
|
||||
"symbol": "At",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q48013": {
|
||||
"si_name": "Q11570",
|
||||
@@ -5705,14 +5810,14 @@
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q50094": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Np",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q50098": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "B",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q50190518": {
|
||||
"si_name": "Q25377184",
|
||||
@@ -5755,9 +5860,9 @@
|
||||
"to_si_factor": 1000.0
|
||||
},
|
||||
"Q524410": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11574",
|
||||
"symbol": "Ga",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 3.15576e+16
|
||||
},
|
||||
"Q531": {
|
||||
"si_name": "Q11573",
|
||||
@@ -5765,9 +5870,9 @@
|
||||
"to_si_factor": 9460730472580800.0
|
||||
},
|
||||
"Q5329": {
|
||||
"si_name": null,
|
||||
"si_name": "Q50098",
|
||||
"symbol": "dB",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.1
|
||||
},
|
||||
"Q53393488": {
|
||||
"si_name": "Q39369",
|
||||
@@ -6410,9 +6515,9 @@
|
||||
"to_si_factor": 3.4262590996353905
|
||||
},
|
||||
"Q549389": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "b/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q550341": {
|
||||
"si_name": "Q550341",
|
||||
@@ -6440,9 +6545,9 @@
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q5558595": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "GFLOPS",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000.0
|
||||
},
|
||||
"Q55663153": {
|
||||
"si_name": "Q55663153",
|
||||
@@ -6519,20 +6624,25 @@
|
||||
"symbol": "GtCO2eq",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q57084839": {
|
||||
"si_name": null,
|
||||
"symbol": "gCDE/km",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q57084901": {
|
||||
"si_name": null,
|
||||
"symbol": "KgCO2eq",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q57084921": {
|
||||
"si_name": null,
|
||||
"si_name": "Q11570",
|
||||
"symbol": "gCO2eq",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.001
|
||||
},
|
||||
"Q5711255": {
|
||||
"si_name": null,
|
||||
"si_name": "Q25517",
|
||||
"symbol": "aL",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1e-21
|
||||
},
|
||||
"Q5711261": {
|
||||
"si_name": "Q25517",
|
||||
@@ -6674,11 +6784,6 @@
|
||||
"symbol": "in",
|
||||
"to_si_factor": 0.0254
|
||||
},
|
||||
"Q61793198": {
|
||||
"si_name": "Q11573",
|
||||
"symbol": "rd",
|
||||
"to_si_factor": 5.02921
|
||||
},
|
||||
"Q61794766": {
|
||||
"si_name": "Q11573",
|
||||
"symbol": "ch (US survey)",
|
||||
@@ -6710,9 +6815,9 @@
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q61995006": {
|
||||
"si_name": null,
|
||||
"si_name": "Q106682512",
|
||||
"symbol": "KWth",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000.0
|
||||
},
|
||||
"Q61996348": {
|
||||
"si_name": "Q794261",
|
||||
@@ -6755,14 +6860,14 @@
|
||||
"to_si_factor": 1.1574074e-05
|
||||
},
|
||||
"Q64740041": {
|
||||
"si_name": null,
|
||||
"si_name": "Q106688958",
|
||||
"symbol": "kWh/(m² yr)",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.000114
|
||||
},
|
||||
"Q64740314": {
|
||||
"si_name": null,
|
||||
"si_name": "Q106688958",
|
||||
"symbol": "kWh/(m² day)",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 41.67
|
||||
},
|
||||
"Q64748817": {
|
||||
"si_name": "Q80374519",
|
||||
@@ -6825,9 +6930,9 @@
|
||||
"to_si_factor": 1016.0469088
|
||||
},
|
||||
"Q66778234": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "TFLOPS",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000000000.0
|
||||
},
|
||||
"Q66778809": {
|
||||
"si_name": null,
|
||||
@@ -6839,6 +6944,11 @@
|
||||
"symbol": "PFLOPS",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q66778951": {
|
||||
"si_name": null,
|
||||
"symbol": "ZFLOPS",
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q67060736": {
|
||||
"si_name": "Q67060736",
|
||||
"symbol": "W/kg",
|
||||
@@ -7225,9 +7335,9 @@
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q7350781": {
|
||||
"si_name": null,
|
||||
"si_name": "Q6137407",
|
||||
"symbol": "Mb/s",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1000000.0
|
||||
},
|
||||
"Q743895": {
|
||||
"si_name": "Q39369",
|
||||
@@ -7545,9 +7655,9 @@
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q836941": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "°Bx",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 0.01
|
||||
},
|
||||
"Q83853845": {
|
||||
"si_name": "Q83853845",
|
||||
@@ -7599,6 +7709,11 @@
|
||||
"symbol": "hm",
|
||||
"to_si_factor": 100.0
|
||||
},
|
||||
"Q84451486": {
|
||||
"si_name": "Q84451486",
|
||||
"symbol": "K m/W",
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q844976": {
|
||||
"si_name": "Q2844478",
|
||||
"symbol": "Oe",
|
||||
@@ -7630,9 +7745,9 @@
|
||||
"to_si_factor": 1000000000.0
|
||||
},
|
||||
"Q855161": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "Yib",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.2089258196146292e+24
|
||||
},
|
||||
"Q856240": {
|
||||
"si_name": "Q794261",
|
||||
@@ -7659,6 +7774,11 @@
|
||||
"symbol": "abA",
|
||||
"to_si_factor": 10.0
|
||||
},
|
||||
"Q86897783": {
|
||||
"si_name": "Q86897783",
|
||||
"symbol": "Pa² s",
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q87047886": {
|
||||
"si_name": "Q87047886",
|
||||
"symbol": "Pa s/m³",
|
||||
@@ -7680,14 +7800,14 @@
|
||||
"to_si_factor": 1e-12
|
||||
},
|
||||
"Q8799": {
|
||||
"si_name": null,
|
||||
"si_name": "Q199",
|
||||
"symbol": "B",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q8805": {
|
||||
"si_name": null,
|
||||
"si_name": "Q8805",
|
||||
"symbol": "bit",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1.0
|
||||
},
|
||||
"Q88296091": {
|
||||
"si_name": "Q25517",
|
||||
@@ -7714,11 +7834,6 @@
|
||||
"symbol": "bu (UK)",
|
||||
"to_si_factor": 0.03636872
|
||||
},
|
||||
"Q89662131": {
|
||||
"si_name": "Q25517",
|
||||
"symbol": "pt (UK)",
|
||||
"to_si_factor": 0.00056826125
|
||||
},
|
||||
"Q89992008": {
|
||||
"si_name": "Q89992008",
|
||||
"symbol": "F⁻¹",
|
||||
@@ -7745,9 +7860,9 @@
|
||||
"to_si_factor": null
|
||||
},
|
||||
"Q9048643": {
|
||||
"si_name": null,
|
||||
"si_name": "Q25517",
|
||||
"symbol": "nl",
|
||||
"to_si_factor": null
|
||||
"to_si_factor": 1e-12
|
||||
},
|
||||
"Q905912": {
|
||||
"si_name": "Q281096",
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
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::
|
||||
|
||||
$ ./manage pyenv.cmd bash --norc --noprofile
|
||||
(py3) python -m searx.enginelib --help
|
||||
$ ./manage dev.env
|
||||
(dev.env)$ python -m searx.enginelib --help
|
||||
|
||||
.. hint::
|
||||
|
||||
@@ -46,6 +46,7 @@ ENGINES_CACHE: ExpireCacheSQLite = ExpireCacheSQLite.build_cache(
|
||||
name="ENGINES_CACHE",
|
||||
MAXHOLD_TIME=60 * 60 * 24 * 7, # 7 days
|
||||
MAINTENANCE_PERIOD=60 * 60, # 2h
|
||||
MAX_VALUE_LEN=1024 * 1024 * 1024, # 1MB
|
||||
)
|
||||
)
|
||||
"""Global :py:obj:`searx.cache.ExpireCacheSQLite` instance where the cached
|
||||
@@ -71,9 +72,9 @@ def state():
|
||||
|
||||
|
||||
@app.command()
|
||||
def maintenance(force: bool = True):
|
||||
def maintenance(force: bool = True, truncate: bool = False):
|
||||
"""Carry out maintenance on cache of the engines."""
|
||||
ENGINES_CACHE.maintenance(force=force)
|
||||
ENGINES_CACHE.maintenance(force=force, truncate=truncate)
|
||||
|
||||
|
||||
class EngineCache:
|
||||
@@ -111,8 +112,8 @@ class EngineCache:
|
||||
For introspection of the DB, jump into developer environment and run command to
|
||||
show cache state::
|
||||
|
||||
$ ./manage pyenv.cmd bash --norc --noprofile
|
||||
(py3) python -m searx.enginelib cache state
|
||||
$ ./manage dev.env
|
||||
(dev.env)$ python -m searx.enginelib cache state
|
||||
|
||||
cache tables and key/values
|
||||
===========================
|
||||
@@ -159,7 +160,8 @@ class EngineCache:
|
||||
def __init__(self, engine_name: str, expire: int | None = None):
|
||||
self.expire: int = expire or ENGINES_CACHE.cfg.MAXHOLD_TIME
|
||||
_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:
|
||||
return ENGINES_CACHE.set(
|
||||
|
||||
@@ -116,19 +116,6 @@ class EngineTraits:
|
||||
return self.all_locale
|
||||
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):
|
||||
"""Create a copy of the dataclass object."""
|
||||
return EngineTraits(**dataclasses.asdict(self))
|
||||
|
||||
@@ -84,6 +84,10 @@ def request(query, params):
|
||||
|
||||
|
||||
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)
|
||||
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
|
||||
@@ -39,7 +39,6 @@ url_xpath = './h4/a/@href'
|
||||
title_xpath = './h4/a[1]'
|
||||
content_xpath = './/p[1]'
|
||||
correction_xpath = '//*[@id="didYouMean"]//a'
|
||||
number_of_results_xpath = '//*[@id="totalResults"]'
|
||||
name_token_xpath = '//form[@id="searchForm"]/input[@type="hidden"]/@name'
|
||||
value_token_xpath = '//form[@id="searchForm"]/input[@type="hidden"]/@value'
|
||||
|
||||
@@ -107,14 +106,6 @@ def response(resp):
|
||||
for correction in eval_xpath_list(dom, correction_xpath):
|
||||
results.append({'correction': extract_text(correction)})
|
||||
|
||||
# get number of results
|
||||
number_of_results = eval_xpath(dom, number_of_results_xpath)
|
||||
if number_of_results:
|
||||
try:
|
||||
results.append({'number_of_results': int(extract_text(number_of_results))})
|
||||
except: # pylint: disable=bare-except
|
||||
pass
|
||||
|
||||
# Update the tokens to the newest ones
|
||||
token_str = _get_tokens(dom)
|
||||
CACHE.set('ahmia-tokens', token_str, expire=60 * 60)
|
||||
|
||||
@@ -60,6 +60,8 @@ base_url = "https://search.aol.com"
|
||||
time_range_map = {"day": "1d", "week": "1w", "month": "1m", "year": "1y"}
|
||||
safesearch_map = {0: "p", 1: "r", 2: "i"}
|
||||
|
||||
enable_http2 = False
|
||||
|
||||
|
||||
def init(_):
|
||||
if search_type not in ("search", "image", "video"):
|
||||
|
||||
@@ -21,7 +21,7 @@ about = {
|
||||
|
||||
categories = ['images']
|
||||
paging = True
|
||||
nb_per_page = 20
|
||||
page_size = 20
|
||||
|
||||
search_api = 'https://api.artic.edu/api/v1/artworks/search?'
|
||||
image_api = 'https://www.artic.edu/iiif/2/'
|
||||
@@ -34,7 +34,7 @@ def request(query, params):
|
||||
'q': query,
|
||||
'page': params['pageno'],
|
||||
'fields': 'id,title,artist_display,medium_display,image_id,date_display,dimensions,artist_titles',
|
||||
'limit': nb_per_page,
|
||||
'limit': page_size,
|
||||
}
|
||||
)
|
||||
params['url'] = search_api + args
|
||||
|
||||
@@ -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
|
||||
@@ -26,7 +26,7 @@ base_url = (
|
||||
|
||||
# engine dependent config
|
||||
paging = True
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
|
||||
# shortcuts for advanced search
|
||||
shortcut_dict = {
|
||||
@@ -57,12 +57,12 @@ def request(query, params):
|
||||
query = re.sub(key, val, query)
|
||||
|
||||
# basic search
|
||||
offset = (params['pageno'] - 1) * number_of_results
|
||||
offset = (params['pageno'] - 1) * page_size
|
||||
|
||||
string_args = {
|
||||
'query': urlencode({'query': query}),
|
||||
'offset': offset,
|
||||
'hits': number_of_results,
|
||||
'hits': page_size,
|
||||
}
|
||||
|
||||
params['url'] = base_url.format(**string_args)
|
||||
|
||||
+3
-16
@@ -13,7 +13,6 @@ implementations are shared by other engines:
|
||||
"""
|
||||
|
||||
import base64
|
||||
import re
|
||||
import typing as t
|
||||
from urllib.parse import parse_qs, urlencode, urlparse
|
||||
|
||||
@@ -48,7 +47,7 @@ _safesearch_map: dict[int, str] = {
|
||||
}
|
||||
"""Filter results. 0: None, 1: Moderate, 2: Strict"""
|
||||
|
||||
base_url = "https://www.bing.com/search"
|
||||
base_url = "https://www.bing.com"
|
||||
"""Bing-Web search URL"""
|
||||
|
||||
|
||||
@@ -94,7 +93,7 @@ def override_accept_language(params: "OnlineParams", engine_region: str | None)
|
||||
params["headers"]["Accept-Language"] = f"{engine_region},{lang};q=0.9"
|
||||
|
||||
|
||||
def request(query: str, params: "OnlineParams") -> "OnlineParams":
|
||||
def request(query: str, params: "OnlineParams"):
|
||||
"""Assemble a Bing-Web request."""
|
||||
|
||||
engine_region = traits.get_region(params["searxng_locale"], traits.all_locale)
|
||||
@@ -110,13 +109,7 @@ def request(query: str, params: "OnlineParams") -> "OnlineParams":
|
||||
if locale_params:
|
||||
query_params.update(locale_params)
|
||||
|
||||
params["url"] = f"{base_url}?{urlencode(query_params)}"
|
||||
|
||||
# in some regions where geoblocking is employed (e.g. China),
|
||||
# www.bing.com redirects to the regional version of Bing
|
||||
params["allow_redirects"] = True
|
||||
|
||||
return params
|
||||
params["url"] = f"{base_url}/search?{urlencode(query_params)}"
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
|
||||
@@ -159,12 +152,6 @@ def response(resp: "SXNG_Response") -> list[dict[str, t.Any]]:
|
||||
|
||||
results.append({"url": href, "title": title, "content": content})
|
||||
|
||||
if results:
|
||||
result_len_container = "".join(eval_xpath(dom, '//span[@class="sb_count"]//text()'))
|
||||
result_len_container = re.sub(r"[^0-9]", "", result_len_container)
|
||||
if result_len_container:
|
||||
results.append({"number_of_results": int(result_len_container)})
|
||||
|
||||
return results
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ time_map = {
|
||||
"year": 60 * 24 * 365,
|
||||
}
|
||||
|
||||
base_url = "https://www.bing.com/images/async"
|
||||
base_url = "https://www.bing.com"
|
||||
"""Bing-Image search URL"""
|
||||
|
||||
|
||||
@@ -64,9 +64,7 @@ def request(query, params):
|
||||
if params["time_range"]:
|
||||
query_params["qft"] = "filterui:age-lt%s" % time_map[params["time_range"]]
|
||||
|
||||
params["url"] = base_url + "?" + urlencode(query_params)
|
||||
|
||||
return params
|
||||
params["url"] = base_url + "/images/async?" + urlencode(query_params)
|
||||
|
||||
|
||||
def response(resp):
|
||||
|
||||
@@ -44,7 +44,7 @@ time_map = {
|
||||
difference of *last day* and *last week* in the result list is just marginally.
|
||||
Bing does not have news range ``year`` / we use ``month`` instead."""
|
||||
|
||||
base_url = "https://www.bing.com/news/infinitescrollajax"
|
||||
base_url = "https://www.bing.com"
|
||||
"""Bing (News) search URL"""
|
||||
|
||||
|
||||
@@ -74,9 +74,7 @@ def request(query, params):
|
||||
if params["time_range"]:
|
||||
query_params["qft"] = time_map.get(params["time_range"], 'interval="9"')
|
||||
|
||||
params["url"] = base_url + "?" + urlencode(query_params)
|
||||
|
||||
return params
|
||||
params["url"] = base_url + "/news/infinitescrollajax?" + urlencode(query_params)
|
||||
|
||||
|
||||
def response(resp):
|
||||
|
||||
@@ -29,7 +29,7 @@ paging = True
|
||||
safesearch = True
|
||||
time_range_support = True
|
||||
|
||||
base_url = "https://www.bing.com/videos/asyncv2"
|
||||
base_url = "https://www.bing.com"
|
||||
"""Bing-Video search URL"""
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ def request(query, params):
|
||||
query_params["form"] = "VRFLTR"
|
||||
query_params["qft"] = " filterui:videoage-lt%s" % time_map[params["time_range"]]
|
||||
|
||||
params["url"] = base_url + "?" + urlencode(query_params)
|
||||
params["url"] = base_url + "/videos/asyncv2?" + urlencode(query_params)
|
||||
|
||||
return params
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -16,7 +16,7 @@ about = {
|
||||
paging = True
|
||||
categories = []
|
||||
|
||||
number_of_results = 20
|
||||
page_size = 20
|
||||
skip_premium = True
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ thumbnail_format = "crop-240x300"
|
||||
|
||||
|
||||
def request(query, params):
|
||||
args = {'query': query, 'limit': number_of_results, 'offset': (params['pageno'] - 1) * number_of_results}
|
||||
args = {'query': query, 'limit': page_size, 'offset': (params['pageno'] - 1) * page_size}
|
||||
params['url'] = f"{base_url}/v2/search-gateway/recipes?{urlencode(args)}"
|
||||
return params
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ the API key in the engine :ref:`core engine config`."""
|
||||
|
||||
categories = ["science", "scientific publications"]
|
||||
paging = True
|
||||
nb_per_page = 10
|
||||
page_size = 10
|
||||
base_url = "https://api.core.ac.uk/v3/search/works/"
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
# API v3 uses different parameters
|
||||
search_params = {
|
||||
"q": query,
|
||||
"offset": (params["pageno"] - 1) * nb_per_page,
|
||||
"limit": nb_per_page,
|
||||
"offset": (params["pageno"] - 1) * page_size,
|
||||
"limit": page_size,
|
||||
"sort": "relevance",
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ about = {
|
||||
# engine dependent config
|
||||
categories = ["videos"]
|
||||
paging = True
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
|
||||
time_range_support = True
|
||||
time_delta_dict = {
|
||||
@@ -113,7 +113,7 @@ def request(query, params):
|
||||
"password_protected": "false",
|
||||
"private": "false",
|
||||
"sort": "relevance",
|
||||
"limit": number_of_results,
|
||||
"limit": page_size,
|
||||
"fields": ",".join(result_fields),
|
||||
}
|
||||
|
||||
|
||||
@@ -109,7 +109,6 @@ def search(query: str, params: "RequestParams") -> EngineResults:
|
||||
kvmap=kvmap,
|
||||
)
|
||||
)
|
||||
res.add(res.types.LegacyResult(number_of_results=count))
|
||||
|
||||
# cache counter value for 20sec
|
||||
CACHE.set("count", count, expire=20)
|
||||
|
||||
@@ -176,6 +176,4 @@ def response(resp):
|
||||
|
||||
results.append(result)
|
||||
|
||||
results.append({'number_of_results': len(json_data['topics'])})
|
||||
|
||||
return results
|
||||
|
||||
@@ -21,7 +21,6 @@ about = {
|
||||
# engine dependent config
|
||||
categories = ['general'] # 'images', 'music', 'videos', 'files'
|
||||
paging = False
|
||||
number_of_results = 5
|
||||
|
||||
# search-url
|
||||
# Doku is OpenSearch compatible
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Duden"""
|
||||
|
||||
import re
|
||||
from urllib.parse import quote, urljoin
|
||||
from lxml import html
|
||||
from searx.utils import extract_text, eval_xpath, eval_xpath_list, eval_xpath_getindex
|
||||
@@ -51,13 +50,6 @@ def response(resp):
|
||||
|
||||
dom = html.fromstring(resp.text)
|
||||
|
||||
number_of_results_element = eval_xpath_getindex(
|
||||
dom, '//a[@class="active" and contains(@href,"/suchen/dudenonline")]/span/text()', 0, default=None
|
||||
)
|
||||
if number_of_results_element is not None:
|
||||
number_of_results_string = re.sub('[^0-9]', '', number_of_results_element)
|
||||
results.append({'number_of_results': int(number_of_results_string)})
|
||||
|
||||
for result in eval_xpath_list(dom, '//section[not(contains(@class, "essay"))]'):
|
||||
url = eval_xpath_getindex(result, './/h2/a', 0).get('href')
|
||||
url = urljoin(base_url, url)
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Flaticon_ is a database for icons.
|
||||
|
||||
.. _Flaticon: https://www.flaticon.com
|
||||
"""
|
||||
|
||||
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://www.flaticon.com",
|
||||
"wikidata_id": "Q105283791",
|
||||
"official_api_documentation": None,
|
||||
"use_official_api": False,
|
||||
"require_api_key": False,
|
||||
"results": "JSON",
|
||||
}
|
||||
|
||||
base_url = "https://www.flaticon.com"
|
||||
|
||||
categories = ["images", "icons"]
|
||||
paging = True
|
||||
|
||||
|
||||
def request(query: str, params: "OnlineParams") -> None:
|
||||
args = {
|
||||
"word": query,
|
||||
}
|
||||
params["headers"].update(
|
||||
{
|
||||
# important: query term is not URL encoded in the referer string
|
||||
"Referer": f"{base_url}/search?word={query}",
|
||||
"X-Requested-With": "XMLHttpRequest",
|
||||
}
|
||||
)
|
||||
params["url"] = f"{base_url}/ajax/search/{params['pageno']}?{urlencode(args)}"
|
||||
|
||||
|
||||
def _fix_url(url: str) -> str:
|
||||
return url.replace(r"\/", "/")
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response"):
|
||||
res = EngineResults()
|
||||
|
||||
result: dict[str, str] # TBH: dict[str, t.Any]
|
||||
for result in resp.json()["items"]:
|
||||
res.add(
|
||||
res.types.Image(
|
||||
title=result["name"],
|
||||
content=", ".join([tag["tag"] for tag in result["tags"]]), # pyright: ignore[reportArgumentType]
|
||||
url=_fix_url(result["slug"]),
|
||||
thumbnail_src=_fix_url(result["png"]),
|
||||
img_src=_fix_url(result["png512"]),
|
||||
author=result["team_name"],
|
||||
)
|
||||
)
|
||||
|
||||
return res
|
||||
@@ -20,7 +20,7 @@ about = {
|
||||
|
||||
categories = ['images']
|
||||
|
||||
nb_per_page = 15
|
||||
page_size = 15
|
||||
paging = True
|
||||
api_key = None
|
||||
|
||||
@@ -29,7 +29,7 @@ url = (
|
||||
'https://api.flickr.com/services/rest/?method=flickr.photos.search'
|
||||
+ '&api_key={api_key}&{text}&sort=relevance'
|
||||
+ '&extras=description%2C+owner_name%2C+url_o%2C+url_n%2C+url_z'
|
||||
+ '&per_page={nb_per_page}&format=json&nojsoncallback=1&page={page}'
|
||||
+ '&per_page={page_size}&format=json&nojsoncallback=1&page={page}'
|
||||
)
|
||||
photo_url = 'https://www.flickr.com/photos/{userid}/{photoid}'
|
||||
|
||||
@@ -42,7 +42,7 @@ def build_flickr_url(user_id, photo_id):
|
||||
|
||||
def request(query, params):
|
||||
params['url'] = url.format(
|
||||
text=urlencode({'text': query}), api_key=api_key, nb_per_page=nb_per_page, page=params['pageno']
|
||||
text=urlencode({'text': query}), api_key=api_key, page_size=page_size, page=params['pageno']
|
||||
)
|
||||
return params
|
||||
|
||||
|
||||
+31
-24
@@ -1,15 +1,23 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Fyyd (podcasts)"""
|
||||
|
||||
import typing as t
|
||||
|
||||
from datetime import datetime
|
||||
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 = {
|
||||
'website': 'https://fyyd.de',
|
||||
'official_api_documentation': 'https://github.com/eazyliving/fyyd-api',
|
||||
'use_official_api': True,
|
||||
'require_api_key': False,
|
||||
'results': 'JSON',
|
||||
"website": "https://fyyd.de",
|
||||
"official_api_documentation": "https://github.com/eazyliving/fyyd-api",
|
||||
"use_official_api": True,
|
||||
"require_api_key": False,
|
||||
"results": "JSON",
|
||||
}
|
||||
categories = []
|
||||
paging = True
|
||||
@@ -18,31 +26,30 @@ base_url = "https://api.fyyd.de"
|
||||
page_size = 10
|
||||
|
||||
|
||||
def request(query, params):
|
||||
def request(query: str, params: "OnlineParams") -> None:
|
||||
args = {
|
||||
'term': query,
|
||||
'count': page_size,
|
||||
'page': params['pageno'] - 1,
|
||||
"term": query,
|
||||
"count": page_size,
|
||||
"page": params["pageno"] - 1,
|
||||
}
|
||||
params['url'] = f"{base_url}/0.2/search/podcast?{urlencode(args)}"
|
||||
return params
|
||||
params["url"] = f"{base_url}/0.2/search/podcast?{urlencode(args)}"
|
||||
|
||||
|
||||
def response(resp):
|
||||
results = []
|
||||
def response(resp: "SXNG_Response"):
|
||||
res = EngineResults()
|
||||
|
||||
json_results = resp.json()['data']
|
||||
json_results: list[dict[str, str]] = resp.json()["data"] # pyright: ignore[reportAny]
|
||||
|
||||
for result in json_results:
|
||||
results.append(
|
||||
{
|
||||
'url': result['htmlURL'],
|
||||
'title': result['title'],
|
||||
'content': result['description'],
|
||||
'thumbnail': result['smallImageURL'],
|
||||
'publishedDate': datetime.strptime(result['status_since'], '%Y-%m-%d %H:%M:%S'),
|
||||
'metadata': f"Rank: {result['rank']} || {result['episode_count']} episodes",
|
||||
}
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=result["htmlURL"],
|
||||
title=result["title"],
|
||||
content=result["description"],
|
||||
thumbnail=result["smallImageURL"],
|
||||
publishedDate=datetime.strptime(result["status_since"], "%Y-%m-%d %H:%M:%S"),
|
||||
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
|
||||
|
||||
|
||||
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"):
|
||||
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:
|
||||
"""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
|
||||
.. _save: https://developers.google.com/custom-search/docs/xml_results#safesp
|
||||
"""
|
||||
import typing as t
|
||||
|
||||
from urllib.parse import urlencode
|
||||
import json
|
||||
import base64
|
||||
from urllib.parse import urlencode
|
||||
from lxml import html
|
||||
import babel
|
||||
|
||||
@@ -44,18 +46,24 @@ from searx.engines.google import (
|
||||
)
|
||||
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 = {
|
||||
"website": 'https://news.google.com',
|
||||
"wikidata_id": 'Q12020',
|
||||
"official_api_documentation": 'https://developers.google.com/custom-search',
|
||||
"website": "https://news.google.com",
|
||||
"wikidata_id": "Q12020",
|
||||
"official_api_documentation": "https://developers.google.com/custom-search",
|
||||
"use_official_api": False,
|
||||
"require_api_key": False,
|
||||
"results": 'HTML',
|
||||
"results": "HTML",
|
||||
}
|
||||
|
||||
# engine dependent config
|
||||
categories = ['news']
|
||||
categories = ["news"]
|
||||
paging = False
|
||||
time_range_support = False
|
||||
|
||||
@@ -64,231 +72,252 @@ time_range_support = False
|
||||
#
|
||||
# safesearch : results are identical for safesearch=0 and safesearch=2
|
||||
safesearch = True
|
||||
base_url: str = "https://news.google.com"
|
||||
|
||||
|
||||
def request(query, params):
|
||||
def request(query: str, params: "OnlineParams") -> None:
|
||||
"""Google-News search request"""
|
||||
|
||||
sxng_locale = params.get('searxng_locale', 'en-US')
|
||||
ceid = locales.get_engine_locale(sxng_locale, traits.custom['ceid'], default='US:en')
|
||||
sxng_locale = params.get("searxng_locale", "en-US")
|
||||
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['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.split('-')
|
||||
ceid_lang.split(":")
|
||||
+ [
|
||||
None,
|
||||
"",
|
||||
]
|
||||
)[: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:
|
||||
google_info['params']['hl'] = ceid_lang + '-' + ceid_region
|
||||
google_info["params"]["hl"] = ceid_lang + "-" + ceid_region
|
||||
else:
|
||||
google_info['params']['hl'] = ceid_lang + '-' + ceid_suffix
|
||||
google_info["params"]["hl"] = ceid_lang + "-" + ceid_suffix
|
||||
|
||||
elif ceid_region.lower() != ceid_lang:
|
||||
|
||||
if ceid_region in ['AT', 'BE', 'CH', 'IL', 'SA', 'IN', 'BD', 'PT']:
|
||||
google_info['params']['hl'] = ceid_lang
|
||||
if ceid_region in ["AT", "BE", "CH", "IL", "SA", "IN", "BD", "PT"]:
|
||||
google_info["params"]["hl"] = ceid_lang
|
||||
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']['gl'] = ceid_region
|
||||
google_info["params"]["lr"] = "lang_" + ceid_lang.split("-")[0]
|
||||
google_info["params"]["gl"] = ceid_region
|
||||
|
||||
query_url = (
|
||||
'https://'
|
||||
+ google_info['subdomain']
|
||||
"https://"
|
||||
+ google_info["subdomain"]
|
||||
+ "/search?"
|
||||
+ urlencode(
|
||||
{
|
||||
'q': query,
|
||||
**google_info['params'],
|
||||
}
|
||||
{"q": query, **google_info["params"]},
|
||||
)
|
||||
# ceid includes a ':' character which must not be urlencoded
|
||||
+ ('&ceid=%s' % ceid)
|
||||
+ ("&ceid=%s" % ceid)
|
||||
)
|
||||
|
||||
params['url'] = query_url
|
||||
params['cookies'] = google_info['cookies']
|
||||
params['headers'].update(google_info['headers'])
|
||||
return params
|
||||
params["url"] = query_url
|
||||
params["cookies"] = google_info["cookies"]
|
||||
params["headers"].update(google_info["headers"])
|
||||
|
||||
|
||||
def response(resp):
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
"""Get response from google's search request"""
|
||||
results = []
|
||||
|
||||
res = EngineResults()
|
||||
|
||||
detect_google_sorry(resp)
|
||||
|
||||
# convert the text to dom
|
||||
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
|
||||
# The href attribute of the <a> tag is a google internal link, we have
|
||||
# to decode
|
||||
url: str = eval_xpath_getindex(result, "./a[@target='_blank']/@href", 0, default=0)
|
||||
if not url:
|
||||
continue
|
||||
if url.startswith("./"):
|
||||
url = base_url + url[1:]
|
||||
|
||||
href = eval_xpath_getindex(result, './article/a/@href', 0)
|
||||
href = href.split('?')[0]
|
||||
href = href.split('/')[-1]
|
||||
href = base64.urlsafe_b64decode(href + '====')
|
||||
href = href[href.index(b'http') :].split(b'\xd2')[0]
|
||||
href = href.decode()
|
||||
# The real URL is often encoded in the "jslog" attribute
|
||||
jslog: str | None = eval_xpath_getindex(result, "./a[@target='_blank']/@jslog", 0, default=None)
|
||||
|
||||
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
|
||||
# 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]'))
|
||||
title = extract_text(eval_xpath(result, "./h4")) or ""
|
||||
|
||||
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.:
|
||||
# "https://lh3.googleusercontent.com/DjhQh7DMszk.....z=-p-h100-w100"
|
||||
# These URL are long but not personalized (double checked via tor).
|
||||
pub_date = extract_text(eval_xpath(result, ".//time"))
|
||||
pub_origin = extract_text(eval_xpath(result, ".//div[contains(@class, 'vr1PYe')]"))
|
||||
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(
|
||||
{
|
||||
'url': href,
|
||||
'title': title,
|
||||
'content': content,
|
||||
'thumbnail': thumbnail,
|
||||
}
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=url,
|
||||
title=title,
|
||||
content=content,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
)
|
||||
|
||||
# return results
|
||||
return results
|
||||
return res
|
||||
|
||||
|
||||
ceid_list = [
|
||||
'AE:ar',
|
||||
'AR:es-419',
|
||||
'AT:de',
|
||||
'AU:en',
|
||||
'BD:bn',
|
||||
'BE:fr',
|
||||
'BE:nl',
|
||||
'BG:bg',
|
||||
'BR:pt-419',
|
||||
'BW:en',
|
||||
'CA:en',
|
||||
'CA:fr',
|
||||
'CH:de',
|
||||
'CH:fr',
|
||||
'CL:es-419',
|
||||
'CN:zh-Hans',
|
||||
'CO:es-419',
|
||||
'CU:es-419',
|
||||
'CZ:cs',
|
||||
'DE:de',
|
||||
'EG:ar',
|
||||
'ES:es',
|
||||
'ET:en',
|
||||
'FR:fr',
|
||||
'GB:en',
|
||||
'GH:en',
|
||||
'GR:el',
|
||||
'HK:zh-Hant',
|
||||
'HU:hu',
|
||||
'ID:en',
|
||||
'ID:id',
|
||||
'IE:en',
|
||||
'IL:en',
|
||||
'IL:he',
|
||||
'IN:bn',
|
||||
'IN:en',
|
||||
'IN:hi',
|
||||
'IN:ml',
|
||||
'IN:mr',
|
||||
'IN:ta',
|
||||
'IN:te',
|
||||
'IT:it',
|
||||
'JP:ja',
|
||||
'KE:en',
|
||||
'KR:ko',
|
||||
'LB:ar',
|
||||
'LT:lt',
|
||||
'LV:en',
|
||||
'LV:lv',
|
||||
'MA:fr',
|
||||
'MX:es-419',
|
||||
'MY:en',
|
||||
'NA:en',
|
||||
'NG:en',
|
||||
'NL:nl',
|
||||
'NO:no',
|
||||
'NZ:en',
|
||||
'PE:es-419',
|
||||
'PH:en',
|
||||
'PK:en',
|
||||
'PL:pl',
|
||||
'PT:pt-150',
|
||||
'RO:ro',
|
||||
'RS:sr',
|
||||
'RU:ru',
|
||||
'SA:ar',
|
||||
'SE:sv',
|
||||
'SG:en',
|
||||
'SI:sl',
|
||||
'SK:sk',
|
||||
'SN:fr',
|
||||
'TH:th',
|
||||
'TR:tr',
|
||||
'TW:zh-Hant',
|
||||
'TZ:en',
|
||||
'UA:ru',
|
||||
'UA:uk',
|
||||
'UG:en',
|
||||
'US:en',
|
||||
'US:es-419',
|
||||
'VE:es-419',
|
||||
'VN:vi',
|
||||
'ZA:en',
|
||||
'ZW:en',
|
||||
"AE:ar",
|
||||
"AR:es-419",
|
||||
"AT:de",
|
||||
"AU:en",
|
||||
"BD:bn",
|
||||
"BE:fr",
|
||||
"BE:nl",
|
||||
"BG:bg",
|
||||
"BR:pt-419",
|
||||
"BW:en",
|
||||
"CA:en",
|
||||
"CA:fr",
|
||||
"CH:de",
|
||||
"CH:fr",
|
||||
"CL:es-419",
|
||||
"CN:zh-Hans",
|
||||
"CO:es-419",
|
||||
"CU:es-419",
|
||||
"CZ:cs",
|
||||
"DE:de",
|
||||
"EE:et",
|
||||
"EG:ar",
|
||||
"ES:ca",
|
||||
"ES:es",
|
||||
"ET:en",
|
||||
"FI:fi",
|
||||
"FR:fr",
|
||||
"GB:en",
|
||||
"GH:en",
|
||||
"GR:el",
|
||||
"HK:zh-Hant",
|
||||
"HU:hu",
|
||||
"ID:en",
|
||||
"ID:id",
|
||||
"IE:en",
|
||||
"IL:en",
|
||||
"IL:he",
|
||||
"IN:bn",
|
||||
"IN:en",
|
||||
"IN:gu",
|
||||
"IN:hi",
|
||||
"IN:ml",
|
||||
"IN:mr",
|
||||
"IN:pa",
|
||||
"IN:ta",
|
||||
"IN:te",
|
||||
"IT:it",
|
||||
"JP:ja",
|
||||
"KE:en",
|
||||
"KR:ko",
|
||||
"LB:ar",
|
||||
"LT:lt",
|
||||
"LV:en",
|
||||
"LV:lv",
|
||||
"MA:fr",
|
||||
"MY:en",
|
||||
"MY:ms",
|
||||
"NA:en",
|
||||
"NG:en",
|
||||
"NL:nl",
|
||||
"NO:no",
|
||||
"NZ:en",
|
||||
"PH:en",
|
||||
"PK:en",
|
||||
"PL:pl",
|
||||
"RO:ro",
|
||||
"RS:sr",
|
||||
"RU:ru",
|
||||
"SA:ar",
|
||||
"SE:sv",
|
||||
"SG:en",
|
||||
"SI:sl",
|
||||
"SK:sk",
|
||||
"SN:fr",
|
||||
"TH:th",
|
||||
"TR:tr",
|
||||
"TZ:en",
|
||||
"UA:ru",
|
||||
"UA:uk",
|
||||
"UG:en",
|
||||
"US:en",
|
||||
"VN:vi",
|
||||
"ZA:en",
|
||||
"ZW:en",
|
||||
]
|
||||
"""List of region/language combinations supported by Google News. Values of the
|
||||
``ceid`` argument of the Google News REST API."""
|
||||
|
||||
|
||||
_skip_values = [
|
||||
'ET:en', # english (ethiopia)
|
||||
'ID:en', # english (indonesia)
|
||||
'LV:en', # english (latvia)
|
||||
"ET:en", # english (ethiopia)
|
||||
"ID:en", # english (indonesia)
|
||||
"LV:en", # english (latvia)
|
||||
]
|
||||
|
||||
_ceid_locale_map = {'NO:no': 'nb-NO'}
|
||||
_ceid_locale_map = {"NO:no": "nb-NO"}
|
||||
|
||||
|
||||
def fetch_traits(engine_traits: EngineTraits):
|
||||
_fetch_traits(engine_traits, add_domains=False)
|
||||
|
||||
engine_traits.custom['ceid'] = {}
|
||||
engine_traits.custom["ceid"] = {}
|
||||
|
||||
for ceid in ceid_list:
|
||||
if ceid in _skip_values:
|
||||
continue
|
||||
|
||||
region, lang = ceid.split(':')
|
||||
x = lang.split('-')
|
||||
region, lang = ceid.split(":")
|
||||
x = lang.split("-")
|
||||
if len(x) > 1:
|
||||
if x[1] not in ['Hant', 'Hans']:
|
||||
if x[1] not in ["Hant", "Hans"]:
|
||||
lang = x[0]
|
||||
|
||||
sxng_locale = _ceid_locale_map.get(ceid, lang + '-' + region)
|
||||
sxng_locale = _ceid_locale_map.get(ceid, lang + "-" + region)
|
||||
try:
|
||||
locale = babel.Locale.parse(sxng_locale, sep='-')
|
||||
locale = babel.Locale.parse(sxng_locale, sep="-")
|
||||
except babel.UnknownLocaleError:
|
||||
print("ERROR: %s -> %s is unknown by babel" % (ceid, sxng_locale))
|
||||
continue
|
||||
|
||||
engine_traits.custom['ceid'][locales.region_tag(locale)] = ceid
|
||||
engine_traits.custom["ceid"][locales.region_tag(locale)] = ceid
|
||||
|
||||
@@ -29,7 +29,7 @@ Time Range:
|
||||
|
||||
Safe-Search:
|
||||
|
||||
- :py:obj:`safe_search_support`
|
||||
- :py:obj:`safesearch`
|
||||
- :py:obj:`safe_search_map`
|
||||
|
||||
Response:
|
||||
@@ -103,7 +103,7 @@ Replacements are:
|
||||
|
||||
``{safe_search}``:
|
||||
Safe-search :py:obj:`URL parameter <safe_search_map>` if engine
|
||||
:py:obj:`supports safe-search <safe_search_support>`. The ``{safe_search}``
|
||||
:py:obj:`supports safe-search <safesearch>`. The ``{safe_search}``
|
||||
replacement is taken from the :py:obj:`safes_search_map`. Filter results::
|
||||
|
||||
0: none, 1: moderate, 2:strict
|
||||
@@ -236,7 +236,7 @@ time_range_map = {
|
||||
year: 365
|
||||
'''
|
||||
|
||||
safe_search_support = False
|
||||
safesearch = False
|
||||
'''Engine supports safe-search.'''
|
||||
|
||||
safe_search_map = {0: '&filter=none', 1: '&filter=moderate', 2: '&filter=strict'}
|
||||
@@ -286,7 +286,6 @@ def do_query(data, q): # pylint: disable=invalid-name
|
||||
qkey = q[0]
|
||||
|
||||
for key, value in iterate(data):
|
||||
|
||||
if len(q) == 1:
|
||||
if key == qkey:
|
||||
ret.append(value)
|
||||
|
||||
@@ -51,7 +51,7 @@ about = {
|
||||
# engine dependent config
|
||||
categories = ['general']
|
||||
paging = True
|
||||
number_of_results = 5
|
||||
page_size = 5
|
||||
|
||||
search_type: str = 'nearmatch'
|
||||
"""Which type of search to perform. One of the following values: ``nearmatch``,
|
||||
@@ -110,7 +110,7 @@ def request(query, params):
|
||||
params['language'] = params['language'].split('-')[0]
|
||||
|
||||
api_url = f"{base_url.rstrip('/')}/{api_path}?".format(language=params['language'])
|
||||
offset = (params['pageno'] - 1) * number_of_results
|
||||
offset = (params['pageno'] - 1) * page_size
|
||||
|
||||
args = {
|
||||
'action': 'query',
|
||||
@@ -118,7 +118,7 @@ def request(query, params):
|
||||
'format': 'json',
|
||||
'srsearch': query,
|
||||
'sroffset': offset,
|
||||
'srlimit': number_of_results,
|
||||
'srlimit': page_size,
|
||||
'srwhat': search_type,
|
||||
'srprop': srprop,
|
||||
'srsort': srsort,
|
||||
|
||||
@@ -14,7 +14,7 @@ about = {
|
||||
}
|
||||
|
||||
# engine dependent config
|
||||
number_of_results = 20 # Don't put this over 5000
|
||||
page_size = 20 # Don't put this over 5000
|
||||
categories = ["it", "packages"]
|
||||
disabled = True
|
||||
shortcut = "cpan"
|
||||
@@ -43,7 +43,7 @@ query_data_template = {
|
||||
{"date": {"order": "desc"}},
|
||||
],
|
||||
'_source': ['documentation', "abstract"],
|
||||
'size': number_of_results,
|
||||
'size': page_size,
|
||||
}
|
||||
search_url = urlunparse(["https", "fastapi.metacpan.org", "/v1/file/_search", "", "", ""])
|
||||
|
||||
@@ -53,7 +53,7 @@ def request(query, params):
|
||||
params["method"] = "POST"
|
||||
query_data = query_data_template
|
||||
query_data["query"]["multi_match"]["query"] = query
|
||||
query_data["from"] = (params["pageno"] - 1) * number_of_results
|
||||
query_data["from"] = (params["pageno"] - 1) * page_size
|
||||
params["json"] = query_data
|
||||
return params
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@ def request(query, params):
|
||||
args = {
|
||||
"q": query,
|
||||
"safe": min(params["safesearch"], 1),
|
||||
language_param: traits.get_language(params["searxng_locale"], traits.custom["language_all"]),
|
||||
region_param: traits.get_region(params["searxng_locale"], traits.custom["region_all"]),
|
||||
}
|
||||
|
||||
if search_type:
|
||||
@@ -76,6 +74,10 @@ def request(query, params):
|
||||
logger.debug(args["since"])
|
||||
|
||||
params["url"] = f"{base_url}/search?{urlencode(args)}"
|
||||
params["cookies"] = {
|
||||
language_param: traits.get_language(params["searxng_locale"], traits.custom["language_all"]),
|
||||
region_param: traits.get_region(params["searxng_locale"], traits.custom["region_all"]),
|
||||
}
|
||||
|
||||
return params
|
||||
|
||||
|
||||
@@ -93,7 +93,6 @@ def search(query, params) -> EngineResults:
|
||||
|
||||
query = _client.find({key: q}).skip((params['pageno'] - 1) * results_per_page).limit(results_per_page)
|
||||
|
||||
res.add(res.types.LegacyResult(number_of_results=query.count()))
|
||||
for row in query:
|
||||
del row['_id']
|
||||
kvmap = {str(k): str(v) for k, v in row.items()}
|
||||
|
||||
@@ -21,15 +21,15 @@ about = {
|
||||
categories = ['images']
|
||||
|
||||
paging = True
|
||||
nb_per_page = 20
|
||||
page_size = 20
|
||||
|
||||
base_url = 'https://api.openverse.org/v1/images/'
|
||||
search_string = '?page={page}&page_size={nb_per_page}&format=json&{query}'
|
||||
search_string = '?page={page}&page_size={page_size}&format=json&{query}'
|
||||
|
||||
|
||||
def request(query, params):
|
||||
|
||||
search_path = search_string.format(query=urlencode({'q': query}), nb_per_page=nb_per_page, page=params['pageno'])
|
||||
search_path = search_string.format(query=urlencode({'q': query}), page_size=page_size, page=params['pageno'])
|
||||
|
||||
params['url'] = base_url + search_path
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ about = {
|
||||
# engine dependent config
|
||||
categories = ['map']
|
||||
paging = False
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
|
||||
# search-url
|
||||
base_url = 'https://photon.komoot.io/'
|
||||
@@ -33,7 +33,7 @@ supported_languages = ['de', 'en', 'fr', 'it']
|
||||
|
||||
# do search-request
|
||||
def request(query, params):
|
||||
params['url'] = base_url + search_string.format(query=urlencode({'q': query}), limit=number_of_results)
|
||||
params['url'] = base_url + search_string.format(query=urlencode({'q': query}), limit=page_size)
|
||||
|
||||
if params['language'] != 'all':
|
||||
language = params['language'].split('_')[0]
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Podcast Index"""
|
||||
|
||||
from urllib.parse import quote_plus
|
||||
from datetime import datetime
|
||||
|
||||
about = {
|
||||
'website': 'https://podcastindex.org',
|
||||
'official_api_documentation': None, # requires an account
|
||||
'use_official_api': False,
|
||||
'require_api_key': False,
|
||||
'results': 'JSON',
|
||||
}
|
||||
categories = []
|
||||
|
||||
base_url = "https://podcastindex.org"
|
||||
|
||||
|
||||
def request(query, params):
|
||||
params['url'] = f"{base_url}/api/search/byterm?q={quote_plus(query)}"
|
||||
return params
|
||||
|
||||
|
||||
def response(resp):
|
||||
results = []
|
||||
|
||||
json = resp.json()
|
||||
|
||||
for result in json['feeds']:
|
||||
results.append(
|
||||
{
|
||||
'url': result['link'],
|
||||
'title': result['title'],
|
||||
'content': result['description'],
|
||||
'thumbnail': result['image'],
|
||||
'publishedDate': datetime.fromtimestamp(result['newestItemPubdate']),
|
||||
'metadata': f"{result['author']}, {result['episodeCount']} episodes",
|
||||
}
|
||||
)
|
||||
|
||||
return results
|
||||
@@ -57,7 +57,7 @@ categories = ["science", "scientific publications"]
|
||||
eutils_api = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
|
||||
|
||||
# engine dependent config
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
pubmed_url = "https://www.ncbi.nlm.nih.gov/pubmed/"
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
{
|
||||
"db": "pubmed",
|
||||
"term": query,
|
||||
"retstart": (params["pageno"] - 1) * number_of_results,
|
||||
"hits": number_of_results,
|
||||
"retstart": (params["pageno"] - 1) * page_size,
|
||||
"hits": page_size,
|
||||
}
|
||||
)
|
||||
esearch_url = f"{eutils_api}/esearch.fcgi?{args}"
|
||||
|
||||
+112
-148
@@ -6,7 +6,6 @@ engineered by reading the network log of https://www.qwant.com/ queries.
|
||||
For Qwant's *web-search* two alternatives are implemented:
|
||||
|
||||
- ``web``: uses the :py:obj:`api_url` which returns a JSON structure
|
||||
- ``web-lite``: uses the :py:obj:`web_lite_url` which returns a HTML page
|
||||
|
||||
|
||||
Configuration
|
||||
@@ -22,7 +21,7 @@ This implementation is used by different qwant engines in the :ref:`settings.yml
|
||||
.. code:: yaml
|
||||
|
||||
- name: qwant
|
||||
qwant_categ: web-lite # alternatively use 'web'
|
||||
qwant_categ: web
|
||||
...
|
||||
- name: qwant news
|
||||
qwant_categ: news
|
||||
@@ -39,6 +38,8 @@ Implementations
|
||||
|
||||
"""
|
||||
|
||||
import typing as t
|
||||
|
||||
from datetime import (
|
||||
datetime,
|
||||
timedelta,
|
||||
@@ -47,8 +48,7 @@ from json import loads
|
||||
from urllib.parse import urlencode
|
||||
|
||||
import babel
|
||||
import lxml
|
||||
from flask_babel import gettext
|
||||
from flask_babel import gettext # pyright: ignore[reportUnknownVariableType]
|
||||
|
||||
from searx.enginelib.traits import EngineTraits
|
||||
from searx.exceptions import (
|
||||
@@ -59,11 +59,13 @@ from searx.exceptions import (
|
||||
)
|
||||
from searx.network import raise_for_httperror
|
||||
from searx.utils import (
|
||||
eval_xpath,
|
||||
eval_xpath_list,
|
||||
extract_text,
|
||||
get_embeded_stream_url,
|
||||
)
|
||||
from searx.result_types import EngineResults
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from searx.search.processors import OnlineParams
|
||||
from searx.extended_types import SXNG_Response
|
||||
|
||||
# about
|
||||
about = {
|
||||
@@ -82,113 +84,66 @@ max_page = 5
|
||||
"""5 pages maximum (``&p=5``): Trying to do more just results in an improper
|
||||
redirect"""
|
||||
|
||||
qwant_categ = None
|
||||
"""One of ``web-lite`` (or ``web``), ``news``, ``images`` or ``videos``"""
|
||||
qwant_categ: str = None # pyright: ignore[reportAssignmentType]
|
||||
"""One of ``web``, ``news``, ``images`` or ``videos``"""
|
||||
|
||||
safesearch = True
|
||||
# safe_search_map = {0: '&safesearch=0', 1: '&safesearch=1', 2: '&safesearch=2'}
|
||||
|
||||
# fmt: off
|
||||
qwant_news_locales = [
|
||||
'ca_ad', 'ca_es', 'ca_fr', 'co_fr', 'de_at', 'de_ch', 'de_de', 'en_au',
|
||||
'en_ca', 'en_gb', 'en_ie', 'en_my', 'en_nz', 'en_us', 'es_ad', 'es_ar',
|
||||
'es_cl', 'es_co', 'es_es', 'es_mx', 'es_pe', 'eu_es', 'eu_fr', 'fc_ca',
|
||||
'fr_ad', 'fr_be', 'fr_ca', 'fr_ch', 'fr_fr', 'it_ch', 'it_it', 'nl_be',
|
||||
'nl_nl', 'pt_ad', 'pt_pt',
|
||||
"ca_ad", "ca_es", "ca_fr", "co_fr", "de_at", "de_ch", "de_de", "en_au",
|
||||
"en_ca", "en_gb", "en_ie", "en_my", "en_nz", "en_us", "es_ad", "es_ar",
|
||||
"es_cl", "es_co", "es_es", "es_mx", "es_pe", "eu_es", "eu_fr", "fc_ca",
|
||||
"fr_ad", "fr_be", "fr_ca", "fr_ch", "fr_fr", "it_ch", "it_it", "nl_be",
|
||||
"nl_nl", "pt_ad", "pt_pt",
|
||||
]
|
||||
# fmt: on
|
||||
|
||||
# search-url
|
||||
|
||||
api_url = "https://api.qwant.com/v3/search/"
|
||||
"""URL of Qwant's API (JSON)"""
|
||||
|
||||
web_lite_url = "https://lite.qwant.com/"
|
||||
"""URL of Qwant-Lite (HTML)"""
|
||||
|
||||
|
||||
def request(query, params):
|
||||
def request(query: str, params: "OnlineParams") -> None:
|
||||
"""Qwant search request"""
|
||||
|
||||
if not query:
|
||||
return None
|
||||
return
|
||||
|
||||
q_locale = traits.get_region(params["searxng_locale"], default="en_US")
|
||||
|
||||
url = api_url + f"{qwant_categ}?"
|
||||
args = {"q": query}
|
||||
results_per_page = 10
|
||||
if qwant_categ == "images":
|
||||
results_per_page = 50
|
||||
args = {
|
||||
"q": query,
|
||||
"count": results_per_page,
|
||||
"locale": q_locale,
|
||||
"offset": (params["pageno"] - 1) * results_per_page,
|
||||
"device": "desktop",
|
||||
"safesearch": params["safesearch"],
|
||||
"tgp": 1,
|
||||
"display": True,
|
||||
"llm": True,
|
||||
}
|
||||
params["raise_for_httperror"] = False
|
||||
|
||||
if qwant_categ == "web-lite":
|
||||
url = web_lite_url + "?"
|
||||
args["locale"] = q_locale.lower()
|
||||
args["l"] = q_locale.split("_")[0]
|
||||
args["s"] = params["safesearch"]
|
||||
args["p"] = params["pageno"]
|
||||
|
||||
params["raise_for_httperror"] = True
|
||||
|
||||
elif qwant_categ == "images":
|
||||
args["count"] = 50
|
||||
args["locale"] = q_locale
|
||||
args["safesearch"] = params["safesearch"]
|
||||
args["tgp"] = 3
|
||||
args["offset"] = (params["pageno"] - 1) * args["count"]
|
||||
|
||||
else: # web, news, videos
|
||||
args["count"] = 10
|
||||
args["locale"] = q_locale
|
||||
args["safesearch"] = params["safesearch"]
|
||||
args["llm"] = "false"
|
||||
args["tgp"] = 3
|
||||
args["offset"] = (params["pageno"] - 1) * args["count"]
|
||||
|
||||
params["url"] = url + urlencode(args)
|
||||
|
||||
return params
|
||||
params["url"] = f"{api_url}{qwant_categ}?{urlencode(args)}"
|
||||
|
||||
|
||||
def response(resp):
|
||||
|
||||
if qwant_categ == "web-lite":
|
||||
return parse_web_lite(resp)
|
||||
return parse_web_api(resp)
|
||||
|
||||
|
||||
def parse_web_lite(resp):
|
||||
"""Parse results from Qwant-Lite"""
|
||||
|
||||
results = []
|
||||
dom = lxml.html.fromstring(resp.text)
|
||||
|
||||
for item in eval_xpath_list(dom, "//section/article"):
|
||||
if eval_xpath(item, "./span[contains(@class, 'tooltip')]"):
|
||||
# ignore randomly interspersed advertising adds
|
||||
continue
|
||||
results.append(
|
||||
{
|
||||
"url": extract_text(eval_xpath(item, "./span[contains(@class, 'url partner')]")),
|
||||
"title": extract_text(eval_xpath(item, "./h2/a")),
|
||||
"content": extract_text(eval_xpath(item, "./p")),
|
||||
}
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
def parse_web_api(resp):
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
"""Parse results from Qwant's API"""
|
||||
# pylint: disable=too-many-locals, too-many-branches, too-many-statements
|
||||
|
||||
results = []
|
||||
res = EngineResults()
|
||||
|
||||
# Try to load JSON result
|
||||
search_results: dict[str, t.Any] = {}
|
||||
try:
|
||||
search_results = loads(resp.text)
|
||||
search_results = resp.json()
|
||||
except ValueError:
|
||||
search_results = {}
|
||||
pass
|
||||
|
||||
data = search_results.get("data", {})
|
||||
data: dict[str, t.Any] = search_results.get("data", {}) # pyright: ignore[reportAny]
|
||||
|
||||
# check for an API error
|
||||
if search_results.get("status") != "success":
|
||||
@@ -207,13 +162,13 @@ def parse_web_api(resp):
|
||||
|
||||
if qwant_categ == "web":
|
||||
# The WEB query contains a list named 'mainline'. This list can contain
|
||||
# different result types (e.g. mainline[0]['type'] returns type of the
|
||||
# result items in mainline[0]['items']
|
||||
# different result types (e.g. mainline[0]["type"] returns type of the
|
||||
# result items in mainline[0]["items"]
|
||||
mainline = data.get("result", {}).get("items", {}).get("mainline", {})
|
||||
else:
|
||||
# Queries on News, Images and Videos do not have a list named 'mainline'
|
||||
# in the response. The result items are directly in the list
|
||||
# result['items'].
|
||||
# result["items"].
|
||||
mainline = data.get("result", {}).get("items", [])
|
||||
mainline = [
|
||||
{"type": qwant_categ, "items": mainline},
|
||||
@@ -221,8 +176,9 @@ def parse_web_api(resp):
|
||||
|
||||
# return empty array if there are no results
|
||||
if not mainline:
|
||||
return []
|
||||
return res
|
||||
|
||||
row: dict[str, t.Any]
|
||||
for row in mainline:
|
||||
mainline_type = row.get("type", "web")
|
||||
if mainline_type != qwant_categ:
|
||||
@@ -232,90 +188,98 @@ def parse_web_api(resp):
|
||||
# ignore adds
|
||||
continue
|
||||
|
||||
mainline_items = row.get("items", [])
|
||||
mainline_items: list[dict[str, t.Any]] = row.get("items", [])
|
||||
for item in mainline_items:
|
||||
title = item.get("title", None)
|
||||
res_url = item.get("url", None)
|
||||
|
||||
title: str = item.get("title", "")
|
||||
res_url: str = item.get("url", "")
|
||||
pub_date: datetime | None = None
|
||||
thumbnail: str = ""
|
||||
content: str = item.get("desc", "")
|
||||
|
||||
_date: float | None = item.get("date")
|
||||
if _date:
|
||||
try:
|
||||
pub_date = datetime.fromtimestamp(_date)
|
||||
except ValueError:
|
||||
# news' date value milli seconds
|
||||
pub_date = datetime.fromtimestamp(_date / 1000)
|
||||
|
||||
if mainline_type == "web":
|
||||
content = item["desc"]
|
||||
results.append(
|
||||
{
|
||||
"title": title,
|
||||
"url": res_url,
|
||||
"content": content,
|
||||
}
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
title=title,
|
||||
url=res_url,
|
||||
content=content,
|
||||
)
|
||||
)
|
||||
|
||||
elif mainline_type == "news":
|
||||
pub_date = item["date"]
|
||||
if pub_date is not None:
|
||||
pub_date = datetime.fromtimestamp(pub_date)
|
||||
news_media = item.get("media", [])
|
||||
thumbnail = None
|
||||
if news_media:
|
||||
thumbnail = news_media[0].get("pict", {}).get("url", None)
|
||||
results.append(
|
||||
{
|
||||
"title": title,
|
||||
"url": res_url,
|
||||
"publishedDate": pub_date,
|
||||
"thumbnail": thumbnail,
|
||||
}
|
||||
thumbnail = news_media[0].get("pict", {}).get("url", "")
|
||||
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
title=title,
|
||||
content=content,
|
||||
url=res_url,
|
||||
publishedDate=pub_date,
|
||||
thumbnail=thumbnail,
|
||||
)
|
||||
)
|
||||
|
||||
elif mainline_type == "images":
|
||||
thumbnail = item["thumbnail"]
|
||||
img_src = item["media"]
|
||||
results.append(
|
||||
{
|
||||
"title": title,
|
||||
"url": res_url,
|
||||
"template": "images.html",
|
||||
"thumbnail_src": thumbnail,
|
||||
"img_src": img_src,
|
||||
"resolution": f"{item['width']} x {item['height']}",
|
||||
"img_format": item.get("thumb_type"),
|
||||
}
|
||||
res.add(
|
||||
res.types.LegacyResult(
|
||||
title=title,
|
||||
url=res_url,
|
||||
template="images.html",
|
||||
thumbnail_src=item["thumbnail"] or "",
|
||||
img_src=item["media"] or "",
|
||||
resolution=f"{item['width']} x {item['height']}",
|
||||
img_format=item.get("thumb_type"),
|
||||
)
|
||||
)
|
||||
|
||||
elif mainline_type == "videos":
|
||||
# some videos do not have a description: while qwant-video
|
||||
# returns an empty string, such video from a qwant-web query
|
||||
# miss the 'desc' key.
|
||||
d, s, c = item.get("desc"), item.get("source"), item.get("channel")
|
||||
content_parts = []
|
||||
|
||||
d: str = item.get("desc", "")
|
||||
s: str = item.get("source", "")
|
||||
c: str = item.get("channel", "")
|
||||
|
||||
content_parts: list[str] = []
|
||||
if d:
|
||||
content_parts.append(d)
|
||||
content_parts.append(f"{d}")
|
||||
if s:
|
||||
content_parts.append("%s: %s " % (gettext("Source"), s))
|
||||
content_parts.append(f"{gettext('Source')}: {s} ")
|
||||
if c:
|
||||
content_parts.append("%s: %s " % (gettext("Channel"), c))
|
||||
content_parts.append(f"{gettext('Channel')}: {c} ")
|
||||
content = " // ".join(content_parts)
|
||||
length = item["duration"]
|
||||
if length is not None:
|
||||
length = timedelta(milliseconds=length)
|
||||
pub_date = item["date"]
|
||||
if pub_date is not None:
|
||||
pub_date = datetime.fromtimestamp(pub_date)
|
||||
thumbnail = item["thumbnail"]
|
||||
|
||||
length = timedelta(milliseconds=(item["duration"] or 0))
|
||||
thumbnail = item["thumbnail"] or ""
|
||||
# from some locations (DE and others?) the s2 link do
|
||||
# response a 'Please wait ..' but does not deliver the thumbnail
|
||||
thumbnail = thumbnail.replace("https://s2.qwant.com", "https://s1.qwant.com", 1)
|
||||
results.append(
|
||||
{
|
||||
"title": title,
|
||||
"url": res_url,
|
||||
"content": content,
|
||||
"iframe_src": get_embeded_stream_url(res_url),
|
||||
"publishedDate": pub_date,
|
||||
"thumbnail": thumbnail,
|
||||
"template": "videos.html",
|
||||
"length": length,
|
||||
}
|
||||
|
||||
res.add(
|
||||
res.types.LegacyResult(
|
||||
title=title,
|
||||
url=res_url,
|
||||
content=content,
|
||||
iframe_src=get_embeded_stream_url(res_url),
|
||||
publishedDate=pub_date,
|
||||
thumbnail=thumbnail,
|
||||
template="videos.html",
|
||||
length=length,
|
||||
)
|
||||
)
|
||||
|
||||
return results
|
||||
return res
|
||||
|
||||
|
||||
def fetch_traits(engine_traits: EngineTraits):
|
||||
@@ -326,7 +290,7 @@ def fetch_traits(engine_traits: EngineTraits):
|
||||
from searx.utils import extr
|
||||
|
||||
resp = get(
|
||||
about["website"],
|
||||
about["website"], # pyright: ignore[reportArgumentType]
|
||||
timeout=5,
|
||||
)
|
||||
if not resp.ok:
|
||||
@@ -336,7 +300,7 @@ def fetch_traits(engine_traits: EngineTraits):
|
||||
|
||||
q_initial_props = loads(json_string)
|
||||
q_locales = q_initial_props.get("locales")
|
||||
eng_tag_list = set()
|
||||
eng_tag_list: set[str] = set()
|
||||
|
||||
for country, v in q_locales.items():
|
||||
for lang in v["langs"]:
|
||||
|
||||
@@ -28,7 +28,7 @@ about = {
|
||||
paging = True
|
||||
categories = ["music", "radio"]
|
||||
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
|
||||
station_filters = [] # ['countrycode', 'language']
|
||||
"""A list of filters to be applied to the search of radio stations. By default
|
||||
@@ -100,8 +100,8 @@ def request(query, params):
|
||||
args = {
|
||||
"name": query,
|
||||
"order": "votes",
|
||||
"offset": (params["pageno"] - 1) * number_of_results,
|
||||
"limit": number_of_results,
|
||||
"offset": (params["pageno"] - 1) * page_size,
|
||||
"limit": page_size,
|
||||
"hidebroken": "true",
|
||||
"reverse": "true",
|
||||
}
|
||||
|
||||
@@ -54,6 +54,4 @@ def response(resp):
|
||||
|
||||
results.extend({'suggestion': s} for s in response_json['suggestions'])
|
||||
|
||||
results.append({'number_of_results': response_json['number_of_results']})
|
||||
|
||||
return results
|
||||
|
||||
@@ -74,7 +74,7 @@ about = {
|
||||
categories = ["science", "scientific publications"]
|
||||
|
||||
paging = True
|
||||
nb_per_page = 10
|
||||
page_size = 10
|
||||
"""Number of results to return in the request, see `Pagination and Limits`_ for
|
||||
more details.
|
||||
|
||||
@@ -109,8 +109,8 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
args = {
|
||||
"api_key": api_key,
|
||||
"q": query,
|
||||
"s": nb_per_page * (params["pageno"] - 1),
|
||||
"p": nb_per_page,
|
||||
"s": page_size * (params["pageno"] - 1),
|
||||
"p": page_size,
|
||||
}
|
||||
params["url"] = f"{base_url}?{urlencode(args)}"
|
||||
# For example, the ``year:`` filter requires a *Premium Plan* subscription.
|
||||
|
||||
@@ -134,7 +134,7 @@ time_range_support = True
|
||||
safesearch = True
|
||||
|
||||
time_range_dict = {"day": "d", "week": "w", "month": "m", "year": "y"}
|
||||
safesearch_dict = {0: "1", 1: "0", 2: "0"}
|
||||
safesearch_dict = {0: "none", 1: "moderate", 2: "heavy"}
|
||||
|
||||
# search-url
|
||||
base_url = "https://www.startpage.com"
|
||||
@@ -251,9 +251,10 @@ def request(query, params):
|
||||
"t": "device",
|
||||
"sc": get_sc_code(params),
|
||||
"with_date": time_range_dict.get(params["time_range"], ""),
|
||||
"abp": "1",
|
||||
"abd": "1",
|
||||
"abe": "1",
|
||||
"qsr": "all",
|
||||
"qadf": safesearch_dict[params["safesearch"]],
|
||||
}
|
||||
|
||||
if engine_language:
|
||||
|
||||
@@ -211,8 +211,4 @@ def response(resp) -> EngineResults:
|
||||
|
||||
# append number of results
|
||||
|
||||
number_of_results = json_data.get('num_matches')
|
||||
if number_of_results:
|
||||
results.append({'number_of_results': number_of_results})
|
||||
|
||||
return results
|
||||
|
||||
+35
-18
@@ -1,56 +1,73 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""MyMemory Translated"""
|
||||
|
||||
import typing as t
|
||||
|
||||
import urllib.parse
|
||||
|
||||
from searx.utils import html_to_text
|
||||
from searx.result_types import EngineResults
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from searx.extended_types import SXNG_Response
|
||||
from searx.search.processors import OnlineDictParams
|
||||
#
|
||||
# about
|
||||
about = {
|
||||
"website": 'https://mymemory.translated.net/',
|
||||
"website": "https://mymemory.translated.net/",
|
||||
"wikidata_id": None,
|
||||
"official_api_documentation": 'https://mymemory.translated.net/doc/spec.php',
|
||||
"official_api_documentation": "https://mymemory.translated.net/doc/spec.php",
|
||||
"use_official_api": True,
|
||||
"require_api_key": False,
|
||||
"results": 'JSON',
|
||||
"results": "JSON",
|
||||
}
|
||||
|
||||
engine_type = 'online_dictionary'
|
||||
categories = ['general', 'translate']
|
||||
engine_type = "online_dictionary"
|
||||
categories = ["general", "translate"]
|
||||
api_url = "https://api.mymemory.translated.net"
|
||||
web_url = "https://mymemory.translated.net"
|
||||
weight = 100
|
||||
|
||||
api_key = ''
|
||||
api_key = ""
|
||||
|
||||
|
||||
def request(query, params): # pylint: disable=unused-argument
|
||||
def request(_: str, params: "OnlineDictParams") -> None:
|
||||
|
||||
args = {"q": params["query"], "langpair": f"{params['from_lang'][1]}|{params['to_lang'][1]}"}
|
||||
args = {
|
||||
"q": params["query"],
|
||||
"langpair": f"{params['from_lang'][1]}|{params['to_lang'][1]}",
|
||||
}
|
||||
if api_key:
|
||||
args["key"] = api_key
|
||||
|
||||
params['url'] = f"{api_url}/get?{urllib.parse.urlencode(args)}"
|
||||
return params
|
||||
|
||||
|
||||
def response(resp) -> EngineResults:
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
|
||||
results = EngineResults()
|
||||
data = resp.json()
|
||||
data: dict[str, t.Any] = resp.json()
|
||||
params: "OnlineDictParams" = resp.search_params # pyright: ignore[reportAssignmentType]
|
||||
|
||||
args = {
|
||||
"q": resp.search_params["query"],
|
||||
"lang": resp.search_params.get("searxng_locale", "en"), # ui language
|
||||
"sl": resp.search_params['from_lang'][1],
|
||||
"tl": resp.search_params['to_lang'][1],
|
||||
"q": params["query"],
|
||||
"lang": params.get("searxng_locale", "en"), # ui language
|
||||
"sl": params["from_lang"][1],
|
||||
"tl": params["to_lang"][1],
|
||||
}
|
||||
|
||||
link = f"{web_url}/search.php?{urllib.parse.urlencode(args)}"
|
||||
text = data['responseData']['translatedText']
|
||||
text: str = html_to_text(data["responseData"]["translatedText"])
|
||||
|
||||
examples = [f"{m['segment']} : {m['translation']}" for m in data['matches'] if m['translation'] != text]
|
||||
examples: set[str] = set()
|
||||
match: dict[str, str]
|
||||
for match in data["matches"]:
|
||||
_text = html_to_text(match["translation"])
|
||||
if _text != text:
|
||||
_seg = html_to_text(match["segment"])
|
||||
examples.add(f"{_seg} : {_text}")
|
||||
|
||||
item = results.types.Translations.Item(text=text, examples=examples)
|
||||
item = results.types.Translations.Item(text=text, examples=list(examples))
|
||||
results.add(results.types.Translations(translations=[item], url=link))
|
||||
|
||||
return results
|
||||
|
||||
@@ -62,7 +62,7 @@ about = {
|
||||
|
||||
categories: list[str] = []
|
||||
paging = True
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
|
||||
wc_api_url = "https://commons.wikimedia.org/w/api.php"
|
||||
wc_search_type: str = ""
|
||||
@@ -107,8 +107,8 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
"generator": "search",
|
||||
"gsrnamespace": "6", # https://www.mediawiki.org/wiki/Help:Namespaces#Renaming_namespaces
|
||||
"gsrprop": "snippet",
|
||||
"gsrlimit": number_of_results,
|
||||
"gsroffset": number_of_results * (params["pageno"] - 1),
|
||||
"gsrlimit": page_size,
|
||||
"gsroffset": page_size * (params["pageno"] - 1),
|
||||
"gsrsearch": f"filetype:{filetype} {query}",
|
||||
# imageinfo: https://commons.wikimedia.org/w/api.php?action=help&modules=query%2Bimageinfo
|
||||
"iiprop": "url|size|mime",
|
||||
|
||||
+116
-73
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""This module implements the Wikidata engine. Some implementations are shared
|
||||
from :ref:`wikipedia engine`.
|
||||
"""This module implements the Wikidata engine.
|
||||
|
||||
Some implementations are shared from :ref:`wikipedia engine`.
|
||||
"""
|
||||
# pylint: disable=missing-class-docstring
|
||||
|
||||
@@ -14,6 +14,7 @@ from json import loads
|
||||
from dateutil.parser import isoparse
|
||||
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.network import post, get
|
||||
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
|
||||
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_ENDPOINT_URL = "https://query.wikidata.org/sparql"
|
||||
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",
|
||||
"P435": "MusicBrainz",
|
||||
"P436": "MusicBrainz",
|
||||
@@ -140,7 +145,6 @@ replace_http_by_https = get_string_replaces_function({"http:": "https:"})
|
||||
|
||||
|
||||
class WDAttribute:
|
||||
__slots__ = ("name",)
|
||||
|
||||
def __init__(self, name: str):
|
||||
self.name: str = name
|
||||
@@ -154,13 +158,13 @@ class WDAttribute:
|
||||
def get_where(self):
|
||||
return "OPTIONAL { ?item wdt:{name} ?{name} . }".replace("{name}", self.name)
|
||||
|
||||
def get_wikibase_label(self):
|
||||
def get_wikibase_label(self) -> str:
|
||||
return ""
|
||||
|
||||
def get_group_by(self):
|
||||
def get_group_by(self) -> str:
|
||||
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")
|
||||
|
||||
def __repr__(self):
|
||||
@@ -168,7 +172,7 @@ class WDAttribute:
|
||||
|
||||
|
||||
class WDAmountAttribute(WDAttribute):
|
||||
def get_select(self):
|
||||
def get_select(self) -> str:
|
||||
return "?{name} ?{name}Unit".replace("{name}", self.name)
|
||||
|
||||
def get_where(self):
|
||||
@@ -178,21 +182,21 @@ class WDAmountAttribute(WDAttribute):
|
||||
'{name}', self.name
|
||||
)
|
||||
|
||||
def get_group_by(self):
|
||||
def get_group_by(self) -> str:
|
||||
return self.get_select()
|
||||
|
||||
def get_str(self, result: dict[str, t.Any], language: str):
|
||||
value = result.get(self.name)
|
||||
unit = result.get(self.name + "Unit")
|
||||
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||
value: str | None = result.get(self.name)
|
||||
unit: str | None = result.get(self.name + "Unit")
|
||||
if unit is not None:
|
||||
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
|
||||
|
||||
|
||||
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")
|
||||
self.language: str = language
|
||||
self.kwargs: dict[str, t.Any] = kwargs or {}
|
||||
@@ -215,7 +219,7 @@ class WDArticle(WDAttribute):
|
||||
def get_group_by(self):
|
||||
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)
|
||||
return result.get(key)
|
||||
|
||||
@@ -227,16 +231,16 @@ class WDLabelAttribute(WDAttribute):
|
||||
def get_where(self):
|
||||
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)
|
||||
|
||||
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")
|
||||
|
||||
|
||||
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__(
|
||||
self,
|
||||
@@ -265,12 +269,12 @@ class WDURLAttribute(WDAttribute):
|
||||
"""
|
||||
|
||||
super().__init__(name)
|
||||
self.url_id = url_id
|
||||
self.url_path_prefix = url_path_prefix
|
||||
self.kwargs = kwargs
|
||||
self.url_id: str | None = url_id
|
||||
self.url_path_prefix: str | None = url_path_prefix
|
||||
self.kwargs: dict[str, t.Any] = kwargs or {}
|
||||
|
||||
def get_str(self, result, language: str):
|
||||
value = result.get(self.name + "s")
|
||||
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||
value: str | None = result.get(self.name + "s")
|
||||
if not value:
|
||||
return None
|
||||
|
||||
@@ -306,16 +310,16 @@ class WDGeoAttribute(WDAttribute):
|
||||
def get_group_by(self):
|
||||
return self.get_select()
|
||||
|
||||
def get_str(self, result, language: str):
|
||||
latitude = result.get(self.name + "Lat")
|
||||
longitude = result.get(self.name + "Long")
|
||||
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||
latitude: str | None = result.get(self.name + "Lat")
|
||||
longitude: str | None = result.get(self.name + "Long")
|
||||
if latitude and longitude:
|
||||
return latitude + " " + longitude
|
||||
return None
|
||||
|
||||
def get_geo_url(self, result, osm_zoom=19):
|
||||
latitude = result.get(self.name + "Lat")
|
||||
longitude = result.get(self.name + "Long")
|
||||
def get_geo_url(self, result: dict[str, t.Any], osm_zoom: int = 19) -> str | None:
|
||||
latitude: str | None = result.get(self.name + "Lat")
|
||||
longitude: str | None = result.get(self.name + "Long")
|
||||
if latitude and longitude:
|
||||
return get_earth_coordinates_url(latitude, longitude, osm_zoom)
|
||||
return None
|
||||
@@ -323,9 +327,9 @@ class WDGeoAttribute(WDAttribute):
|
||||
|
||||
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)
|
||||
self.priority = priority
|
||||
self.priority: int = priority
|
||||
|
||||
|
||||
class WDDateAttribute(WDAttribute):
|
||||
@@ -349,11 +353,11 @@ class WDDateAttribute(WDAttribute):
|
||||
def get_group_by(self):
|
||||
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
|
||||
return value
|
||||
|
||||
def format_9(self, value, locale: str):
|
||||
def format_9(self, value: str, locale: str) -> str:
|
||||
year = int(value)
|
||||
# precision: year
|
||||
if year < 1584:
|
||||
@@ -363,17 +367,17 @@ class WDDateAttribute(WDAttribute):
|
||||
timestamp = isoparse(value)
|
||||
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
|
||||
timestamp = isoparse(value)
|
||||
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
|
||||
timestamp = isoparse(value)
|
||||
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)
|
||||
# precision: minute
|
||||
return (
|
||||
@@ -383,11 +387,11 @@ class WDDateAttribute(WDAttribute):
|
||||
.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.
|
||||
return format_datetime(isoparse(value), format="full", locale=locale)
|
||||
|
||||
DATE_FORMAT = {
|
||||
DATE_FORMAT: dict[str, tuple[str, int]] = {
|
||||
"0": ("format_8", 1000000000),
|
||||
"1": ("format_8", 100000000),
|
||||
"2": ("format_8", 10000000),
|
||||
@@ -405,15 +409,15 @@ class WDDateAttribute(WDAttribute):
|
||||
"14": ("format_14", 0), # second
|
||||
}
|
||||
|
||||
def get_str(self, result, language):
|
||||
value = result.get(self.name)
|
||||
def get_str(self, result: dict[str, t.Any], language: str) -> str | None:
|
||||
value: str | None = result.get(self.name)
|
||||
if value == "" or value is None:
|
||||
return None
|
||||
precision = result.get(self.name + "timePrecision")
|
||||
date_format = WDDateAttribute.DATE_FORMAT.get(precision)
|
||||
_p: str = result.get(self.name + "timePrecision") or "1"
|
||||
date_format = WDDateAttribute.DATE_FORMAT.get(_p)
|
||||
if date_format is not None:
|
||||
format_method = getattr(self, date_format[0])
|
||||
precision = date_format[1]
|
||||
precision: int = date_format[1]
|
||||
try:
|
||||
if precision >= 1:
|
||||
_t = value.split("-")
|
||||
@@ -427,9 +431,25 @@ class WDDateAttribute(WDAttribute):
|
||||
return value
|
||||
|
||||
|
||||
WDAttrType = (
|
||||
WDAttribute
|
||||
| WDAmountAttribute
|
||||
| WDArticle
|
||||
| WDLabelAttribute
|
||||
| WDURLAttribute
|
||||
| WDGeoAttribute
|
||||
| WDImageAttribute
|
||||
| WDDateAttribute
|
||||
)
|
||||
WDAttrList = list[WDAttrType]
|
||||
|
||||
|
||||
def get_headers() -> dict[str, str]:
|
||||
# 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:
|
||||
@@ -445,7 +465,7 @@ def get_label_for_entity(entity_id: str, language: str) -> str:
|
||||
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":
|
||||
# query will be cached by wikidata
|
||||
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:
|
||||
|
||||
attributes: tuple[str, list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute]]
|
||||
attributes: WDAttrList
|
||||
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))
|
||||
|
||||
params["method"] = "POST"
|
||||
params["url"] = SPARQL_ENDPOINT_URL
|
||||
params["data"] = {"query": query}
|
||||
params["headers"] = get_headers()
|
||||
|
||||
# additional parameters (not a part of OnlineParams)
|
||||
params["language"] = eng_tag # 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]] = []
|
||||
jsonresponse = loads(resp.content.decode())
|
||||
|
||||
# additional parameters ..
|
||||
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))
|
||||
|
||||
seen_entities: set[str] = set()
|
||||
for result in jsonresponse.get("results", {}).get("bindings", []):
|
||||
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:
|
||||
seen_entities.add(entity_url)
|
||||
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/"
|
||||
|
||||
|
||||
def get_thumbnail(img_src: str) -> str:
|
||||
def get_thumbnail(img_src: str | None) -> str | None:
|
||||
"""Get Thumbnail image from wikimedia commons
|
||||
|
||||
Images from commons.wikimedia.org are (HTTP) redirected to
|
||||
@@ -539,53 +563,58 @@ def get_thumbnail(img_src: str) -> str:
|
||||
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
|
||||
results = []
|
||||
infobox_title = attribute_result.get("itemLabel")
|
||||
results: list[dict[str, t.Any]] = []
|
||||
infobox_title: str = attribute_result.get("itemLabel") # pyright: ignore[reportAssignmentType]
|
||||
infobox_id = attribute_result["item"]
|
||||
infobox_id_lang = None
|
||||
infobox_urls = []
|
||||
infobox_attributes = []
|
||||
infobox_id_lang: str | None = None
|
||||
infobox_urls: list[dict[str, str]] = []
|
||||
infobox_attributes: list[dict[str, str]] = []
|
||||
infobox_content = attribute_result.get("itemDescription", [])
|
||||
img_src = None
|
||||
img_src: str | None = None
|
||||
img_src_priority = 0
|
||||
|
||||
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 != "":
|
||||
attribute_type = type(attribute)
|
||||
|
||||
if attribute_type in (WDURLAttribute, WDArticle):
|
||||
if isinstance(attribute, (WDURLAttribute, WDArticle)):
|
||||
# get_select() method : there is group_concat(distinct ...;separator=", ")
|
||||
# split the value here
|
||||
for url in value.split(", "):
|
||||
infobox_urls.append({"title": attribute.get_label(language), "url": url, **attribute.kwargs})
|
||||
# "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})
|
||||
|
||||
# update the infobox_id with the 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"
|
||||
):
|
||||
infobox_id_lang = attribute.language
|
||||
infobox_id = url
|
||||
elif attribute_type == WDImageAttribute:
|
||||
elif isinstance(attribute, WDImageAttribute):
|
||||
# this attribute is an image.
|
||||
# replace the current image only the priority is lower
|
||||
# (the infobox contain only one image).
|
||||
if attribute.priority > img_src_priority:
|
||||
img_src = get_thumbnail(value)
|
||||
img_src_priority = attribute.priority
|
||||
elif attribute_type == WDGeoAttribute:
|
||||
elif isinstance(attribute, WDGeoAttribute):
|
||||
# geocoordinate link
|
||||
# use the area to get the OSM zoom
|
||||
# Note: ignore the unit (must be km² otherwise the calculation is wrong)
|
||||
# Should use normalized value p:P2046/psn:P2046/wikibase:quantityAmount
|
||||
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)
|
||||
if url:
|
||||
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
|
||||
|
||||
|
||||
def get_query(
|
||||
query: str, language: str
|
||||
) -> tuple[str, list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute]]:
|
||||
def get_query(query: str, language: str) -> tuple[str, WDAttrList]:
|
||||
attributes = get_attributes(language)
|
||||
select = [a.get_select() 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):
|
||||
# pylint: disable=too-many-statements
|
||||
attributes: list[WDAttribute | WDAmountAttribute | WDLabelAttribute | WDImageAttribute] = []
|
||||
attributes: WDAttrList = []
|
||||
|
||||
def add_value(name: str):
|
||||
attributes.append(WDAttribute(name))
|
||||
@@ -654,7 +681,7 @@ def get_attributes(language: str):
|
||||
def add_label(name: str):
|
||||
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))
|
||||
|
||||
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)
|
||||
|
||||
# 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)
|
||||
if not language.startswith("en"):
|
||||
attributes.append(WDArticle("en")) # wikipedia (english)
|
||||
@@ -796,7 +824,19 @@ def debug_explain_wikidata_query(query: str, method: str = "GET"):
|
||||
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
|
||||
for k, v in WIKIDATA_UNITS.items():
|
||||
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:
|
||||
wikidata_property_names.append("wd:" + attribute.name)
|
||||
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", {}):
|
||||
name_field = result.get("name")
|
||||
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/", "")
|
||||
WIKIDATA_PROPERTIES[(entity_id, lang)] = name.capitalize()
|
||||
|
||||
CACHE.set(key="WIKIDATA_PROPERTIES", value=WIKIDATA_PROPERTIES)
|
||||
|
||||
|
||||
def fetch_traits(engine_traits: EngineTraits):
|
||||
"""Uses languages evaluated from :py:obj:`wikipedia.fetch_wikimedia_traits
|
||||
|
||||
@@ -31,7 +31,7 @@ Time Range:
|
||||
|
||||
Safe-Search:
|
||||
|
||||
- :py:obj:`safe_search_support`
|
||||
- :py:obj:`safesearch`
|
||||
- :py:obj:`safe_search_map`
|
||||
|
||||
Response:
|
||||
@@ -100,7 +100,7 @@ Replacements are:
|
||||
|
||||
``{safe_search}``:
|
||||
Safe-search :py:obj:`URL parameter <safe_search_map>` if engine
|
||||
:py:obj:`supports safe-search <safe_search_support>`. The ``{safe_search}``
|
||||
:py:obj:`supports safe-search <safesearch>`. The ``{safe_search}``
|
||||
replacement is taken from the :py:obj:`safes_search_map`. Filter results::
|
||||
|
||||
0: none, 1: moderate, 2:strict
|
||||
@@ -205,7 +205,7 @@ time_range_map = {
|
||||
year: 365
|
||||
'''
|
||||
|
||||
safe_search_support = False
|
||||
safesearch = False
|
||||
'''Engine supports safe-search.'''
|
||||
|
||||
safe_search_map = {0: '&filter=none', 1: '&filter=moderate', 2: '&filter=strict'}
|
||||
@@ -280,7 +280,6 @@ def response(resp) -> EngineResults: # pylint: disable=too-many-branches
|
||||
|
||||
if results_xpath:
|
||||
for result in eval_xpath_list(dom, results_xpath):
|
||||
|
||||
url = extract_url(eval_xpath_list(result, url_xpath, min_len=1), search_url)
|
||||
title = extract_text(eval_xpath_list(result, title_xpath, min_len=1))
|
||||
content = extract_text(eval_xpath_list(result, content_xpath))
|
||||
|
||||
@@ -75,7 +75,7 @@ about = {
|
||||
# engine dependent config
|
||||
categories = ['general']
|
||||
paging = True
|
||||
number_of_results = 10
|
||||
page_size = 10
|
||||
http_digest_auth_user = ""
|
||||
"""HTTP digest user for the local YACY instance"""
|
||||
http_digest_auth_pass = ""
|
||||
@@ -125,11 +125,11 @@ def _base_url() -> str:
|
||||
|
||||
def request(query, params):
|
||||
|
||||
offset = (params['pageno'] - 1) * number_of_results
|
||||
offset = (params['pageno'] - 1) * page_size
|
||||
args = {
|
||||
'query': query,
|
||||
'startRecord': offset,
|
||||
'maximumRecords': number_of_results,
|
||||
'maximumRecords': page_size,
|
||||
'contentdom': search_type,
|
||||
'resource': search_mode,
|
||||
}
|
||||
|
||||
+12
-11
@@ -87,7 +87,6 @@ def request(query, params):
|
||||
|
||||
def response(resp):
|
||||
if search_type == 'web':
|
||||
|
||||
catch_bad_response(resp)
|
||||
|
||||
dom = html.fromstring(resp.text)
|
||||
@@ -106,7 +105,6 @@ def response(resp):
|
||||
return results
|
||||
|
||||
if search_type == 'images':
|
||||
|
||||
catch_bad_response(resp)
|
||||
|
||||
html_data = html.fromstring(resp.text)
|
||||
@@ -127,22 +125,25 @@ def response(resp):
|
||||
for _, item_data in json_resp['initialState']['serpList']['items']['entities'].items():
|
||||
title = item_data['snippet']['title']
|
||||
source = item_data['snippet']['url']
|
||||
thumb = item_data['image']
|
||||
fullsize_image = item_data['viewerData']['dups'][0]['url']
|
||||
height = item_data['viewerData']['dups'][0]['h']
|
||||
width = item_data['viewerData']['dups'][0]['w']
|
||||
filesize = item_data['viewerData']['dups'][0]['fileSizeInBytes']
|
||||
humanized_filesize = humanize_bytes(filesize)
|
||||
|
||||
image_source = item_data["viewerData"]["thumb"]
|
||||
for i in item_data['viewerData']['dups'] + item_data['viewerData']['preview']:
|
||||
if i["h"] > image_source["h"]:
|
||||
image_source = i
|
||||
|
||||
humanized_filesize = None
|
||||
if image_source.get("fileSizeInBytes"):
|
||||
humanized_filesize = humanize_bytes(image_source["fileSizeInBytes"])
|
||||
|
||||
results.append(
|
||||
{
|
||||
'title': title,
|
||||
'url': source,
|
||||
'img_src': fullsize_image,
|
||||
'img_src': image_source["url"],
|
||||
'filesize': humanized_filesize,
|
||||
'thumbnail_src': thumb,
|
||||
'thumbnail_src': item_data["image"],
|
||||
'template': 'images.html',
|
||||
'resolution': f'{width} x {height}',
|
||||
'resolution': f'{image_source["w"]} x {image_source["h"]}',
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
+82
-2
@@ -1,14 +1,17 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Yep (general, images, news)"""
|
||||
|
||||
import re
|
||||
|
||||
import typing as t
|
||||
|
||||
from urllib.parse import urlencode
|
||||
|
||||
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:
|
||||
from searx.enginelib.traits import EngineTraits
|
||||
from searx.extended_types import SXNG_Response
|
||||
from searx.search.processors import OnlineParams
|
||||
|
||||
@@ -29,10 +32,18 @@ enable_http2 = False
|
||||
|
||||
results_per_page = 20
|
||||
|
||||
_IMPORT_RE = re.compile(r"import\"(.*?)\";")
|
||||
_LANGUAGE_RE = re.compile(r"\{english:\".*?\",code_string:\"(.*?)\",code:\".*?\"\}")
|
||||
|
||||
|
||||
def request(query: str, params: 'OnlineParams') -> None:
|
||||
args = {'query': query, 'safeSearch': safesearch_map[params['safesearch']], 'limit': results_per_page}
|
||||
params['url'] = f"{base_url}/fs/2/search?{urlencode(args)}"
|
||||
|
||||
engine_language: str = traits.get_language(params["searxng_locale"])
|
||||
if engine_language:
|
||||
args["hl"] = engine_language
|
||||
|
||||
params['url'] = f"{base_url}/search?{urlencode(args)}"
|
||||
params['headers']['Referer'] = 'https://yep.com/'
|
||||
params['headers']['Origin'] = 'https://yep.com'
|
||||
|
||||
@@ -50,3 +61,72 @@ def response(resp: 'SXNG_Response') -> EngineResults:
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
@@ -30,7 +30,7 @@ import httpx
|
||||
if typing.TYPE_CHECKING:
|
||||
import searx.preferences
|
||||
import searx.results
|
||||
from searx.search.processors import OnlineParamTypes
|
||||
from searx.search.processors import OnlineParamTypes, OnlineDictParams, OnlineCurrenciesParams
|
||||
|
||||
|
||||
class SXNG_Request(flask.Request):
|
||||
@@ -83,4 +83,4 @@ class SXNG_Response(httpx.Response):
|
||||
"""
|
||||
|
||||
ok: bool
|
||||
search_params: "OnlineParamTypes"
|
||||
search_params: "OnlineParamTypes | OnlineDictParams | OnlineCurrenciesParams"
|
||||
|
||||
@@ -16,12 +16,12 @@ IMDB_PREFIX_TO_URL_ID = {
|
||||
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]
|
||||
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):
|
||||
return url[len(HTTP_WIKIMEDIA_IMAGE) :]
|
||||
if url.startswith('File:'):
|
||||
@@ -29,7 +29,7 @@ def get_wikimedia_image_id(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.
|
||||
|
||||
url_id can take value from data/external_urls.json
|
||||
|
||||
@@ -35,6 +35,7 @@ from .keyvalue import KeyValue
|
||||
from .code import Code
|
||||
from .paper import Paper
|
||||
from .file import File
|
||||
from .image import Image
|
||||
|
||||
|
||||
class ResultList(list[Result | LegacyResult], abc.ABC):
|
||||
@@ -50,6 +51,7 @@ class ResultList(list[Result | LegacyResult], abc.ABC):
|
||||
Code = Code
|
||||
Paper = Paper
|
||||
File = File
|
||||
Image = Image
|
||||
MainResult = MainResult
|
||||
Result = Result
|
||||
Translations = Translations
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
__all__ = ["Result"]
|
||||
|
||||
import typing as t
|
||||
import types
|
||||
|
||||
import re
|
||||
import urllib.parse
|
||||
@@ -29,7 +30,9 @@ from collections.abc import Callable
|
||||
|
||||
import msgspec
|
||||
|
||||
from searx import logger as log
|
||||
from searx import logger
|
||||
|
||||
log = logger.getChild("result_types")
|
||||
|
||||
WHITESPACE_REGEX = re.compile('( |\t|\n)+', re.M | re.U)
|
||||
UNSET = object()
|
||||
@@ -125,8 +128,20 @@ def _filter_urls(
|
||||
if not url_src:
|
||||
continue
|
||||
|
||||
new_url = filter_func(result, field_name, url_src)
|
||||
# log.debug("filter_urls: filter_func(result, %s) '%s' -> '%s'", field_name, field_value, new_url)
|
||||
try:
|
||||
new_url = filter_func(result, field_name, url_src)
|
||||
except Exception as exc: # pylint: disable=broad-exception-caught
|
||||
# pylint: disable=no-member
|
||||
_tb: types.TracebackType = exc.__traceback__.tb_next.tb_next # type: ignore
|
||||
log.error(
|
||||
"filter_urls (field '%s'): ignore %s from callback %s:%s",
|
||||
field_name,
|
||||
repr(exc),
|
||||
_tb.tb_frame.f_code.co_filename,
|
||||
_tb.tb_lineno,
|
||||
)
|
||||
continue
|
||||
|
||||
if isinstance(new_url, bool):
|
||||
if new_url:
|
||||
# log.debug("filter_urls: unchanged field %s URL %s", field_name, field_value)
|
||||
@@ -529,7 +544,7 @@ class LegacyResult(dict[str, t.Any]):
|
||||
# the img_src are equal.
|
||||
return hash(f"{self.template}|{self.url}|{self.img_src}")
|
||||
|
||||
if not any(cls in self for cls in ["suggestion", "correction", "infobox", "number_of_results", "engine_data"]):
|
||||
if not any(cls in self for cls in ["suggestion", "correction", "infobox", "engine_data"]):
|
||||
# Ordinary url-results are equal if their values for template,
|
||||
# parsed_url (without schema) and img_src` are equal.
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
"""Typification of the *image* results. Results of this type are rendered in
|
||||
the :origin:`images.html <searx/templates/simple/result_templates/images.html>`
|
||||
template.
|
||||
|
||||
.. autoclass:: Image
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ["Image"]
|
||||
|
||||
import typing as t
|
||||
|
||||
|
||||
from ._base import MainResult
|
||||
|
||||
|
||||
@t.final
|
||||
class Image(MainResult, kw_only=True):
|
||||
"""Result type suitable for displaying images.
|
||||
|
||||
The images are displayed as small thumbnails in the main results list.
|
||||
Clicking on the preview opens a gallery view in which all further metadata
|
||||
for the image is displayed."""
|
||||
|
||||
template: str = "images.html"
|
||||
|
||||
thumbnail_src: str = ""
|
||||
"""URL of a preview of the image."""
|
||||
|
||||
resolution: str = ""
|
||||
"""The resolution of the image (e.g. ``1920 x 1080`` pixel)"""
|
||||
|
||||
img_format: str = ""
|
||||
"""The format of the image (e.g. ``png``)."""
|
||||
|
||||
source: str = ""
|
||||
"""Source of the image."""
|
||||
|
||||
filesize: str = ""
|
||||
"""Size of bytes in :py:obj:`human readable <searx.humanize_bytes>` notation
|
||||
(e.g. ``1MB`` for ``1024*1024`` Bytes filesize)."""
|
||||
@@ -69,7 +69,6 @@ class ResultContainer:
|
||||
self.answers = AnswerSet()
|
||||
self.corrections = set()
|
||||
|
||||
self._number_of_results: list[int] = []
|
||||
self.engine_data: dict[str, dict[str, str]] = defaultdict(dict)
|
||||
self._closed: bool = False
|
||||
self.paging: bool = False
|
||||
@@ -135,11 +134,6 @@ class ResultContainer:
|
||||
self._merge_infobox(result)
|
||||
continue
|
||||
|
||||
if "number_of_results" in result:
|
||||
if self.on_result(result):
|
||||
self._number_of_results.append(result["number_of_results"])
|
||||
continue
|
||||
|
||||
if "engine_data" in result:
|
||||
if self.on_result(result):
|
||||
if result.engine:
|
||||
@@ -252,25 +246,6 @@ class ResultContainer:
|
||||
self._main_results_sorted = gresults
|
||||
return self._main_results_sorted
|
||||
|
||||
@property
|
||||
def number_of_results(self) -> int:
|
||||
"""Returns the average of results number, returns zero if the average
|
||||
result number is smaller than the actual result count."""
|
||||
|
||||
if not self._closed:
|
||||
log.error("call to ResultContainer.number_of_results before ResultContainer.close")
|
||||
return 0
|
||||
|
||||
with self._lock:
|
||||
resultnum_sum = sum(self._number_of_results)
|
||||
if not resultnum_sum or not self._number_of_results:
|
||||
return 0
|
||||
|
||||
average = int(resultnum_sum / len(self._number_of_results))
|
||||
if average < len(self.get_ordered_results()):
|
||||
average = 0
|
||||
return average
|
||||
|
||||
def add_unresponsive_engine(self, engine_name: str, error_type: str, suspended: bool = False):
|
||||
with self._lock:
|
||||
if self._closed:
|
||||
|
||||
+29
-11
@@ -302,7 +302,7 @@ engines:
|
||||
- name: 360search
|
||||
engine: 360search
|
||||
shortcut: 360so
|
||||
timeout: 10.0
|
||||
timeout: 20.0
|
||||
disabled: true
|
||||
|
||||
- name: 360search videos
|
||||
@@ -310,6 +310,12 @@ engines:
|
||||
shortcut: 360sov
|
||||
disabled: true
|
||||
|
||||
- name: 500px
|
||||
engine: 500px
|
||||
shortcut: "500"
|
||||
disabled: true
|
||||
timeout: 5
|
||||
|
||||
- name: 9gag
|
||||
engine: 9gag
|
||||
shortcut: 9g
|
||||
@@ -469,11 +475,6 @@ engines:
|
||||
engine: arxiv
|
||||
shortcut: arx
|
||||
|
||||
- name: ask
|
||||
engine: ask
|
||||
shortcut: ask
|
||||
disabled: true
|
||||
|
||||
- name: azure
|
||||
engine: azure
|
||||
shortcut: az
|
||||
@@ -530,18 +531,22 @@ engines:
|
||||
engine: bing
|
||||
shortcut: bi
|
||||
disabled: true
|
||||
# base_url: https://cn.bing.com # for instances hosted in China
|
||||
|
||||
- name: bing images
|
||||
engine: bing_images
|
||||
shortcut: bii
|
||||
# base_url: https://cn.bing.com # for instances hosted in China
|
||||
|
||||
- name: bing news
|
||||
engine: bing_news
|
||||
shortcut: bin
|
||||
# base_url: https://cn.bing.com # for instances hosted in China
|
||||
|
||||
- name: bing videos
|
||||
engine: bing_videos
|
||||
shortcut: biv
|
||||
# base_url: https://cn.bing.com # for instances hosted in China
|
||||
|
||||
- name: bitchute
|
||||
engine: bitchute
|
||||
@@ -600,6 +605,11 @@ engines:
|
||||
shortcut: cos
|
||||
disabled: true
|
||||
|
||||
- name: cara
|
||||
engine: cara
|
||||
shortcut: ca
|
||||
disabled: true
|
||||
|
||||
- name: chefkoch
|
||||
engine: chefkoch
|
||||
shortcut: chef
|
||||
@@ -880,6 +890,11 @@ engines:
|
||||
shortcut: ftm
|
||||
disabled: true
|
||||
|
||||
- name: flaticon
|
||||
engine: flaticon
|
||||
shortcut: fli
|
||||
disabled: true
|
||||
|
||||
- name: flickr
|
||||
categories: images
|
||||
shortcut: fl
|
||||
@@ -1203,6 +1218,7 @@ engines:
|
||||
categories: [general, web]
|
||||
search_type: web
|
||||
shortcut: ka
|
||||
inactive: true
|
||||
|
||||
- name: karmasearch images
|
||||
engine: karmasearch
|
||||
@@ -1210,18 +1226,21 @@ engines:
|
||||
search_type: images
|
||||
shortcut: kai
|
||||
paging: false
|
||||
inactive: true
|
||||
|
||||
- name: karmasearch videos
|
||||
engine: karmasearch
|
||||
categories: [videos, web]
|
||||
search_type: videos
|
||||
shortcut: kav
|
||||
inactive: true
|
||||
|
||||
- name: karmasearch news
|
||||
engine: karmasearch
|
||||
categories: [news, web]
|
||||
search_type: news
|
||||
shortcut: kan
|
||||
inactive: true
|
||||
|
||||
- name: kickass
|
||||
engine: kickass
|
||||
@@ -1381,7 +1400,6 @@ engines:
|
||||
engine: metacpan
|
||||
shortcut: cpan
|
||||
disabled: true
|
||||
number_of_results: 20
|
||||
|
||||
# https://docs.searxng.org/dev/engines/offline/search-indexer-engines.html#module-searx.engines.meilisearch
|
||||
# - name: meilisearch
|
||||
@@ -1679,10 +1697,6 @@ engines:
|
||||
# image proxy of https://pixiv.perennialte.ch
|
||||
# - https://pximg.perennialte.ch
|
||||
|
||||
- name: podcastindex
|
||||
engine: podcastindex
|
||||
shortcut: podcast
|
||||
|
||||
# Required dependency: psychopg2
|
||||
# - name: postgresql
|
||||
# engine: postgresql
|
||||
@@ -1788,6 +1802,7 @@ engines:
|
||||
shortcut: qwn
|
||||
categories: news
|
||||
network: qwant
|
||||
disabled: true
|
||||
|
||||
- name: qwant images
|
||||
qwant_categ: images
|
||||
@@ -1795,6 +1810,7 @@ engines:
|
||||
shortcut: qwi
|
||||
categories: [images, web]
|
||||
network: qwant
|
||||
disabled: true
|
||||
|
||||
- name: qwant videos
|
||||
qwant_categ: videos
|
||||
@@ -1802,6 +1818,7 @@ engines:
|
||||
shortcut: qwv
|
||||
categories: [videos, web]
|
||||
network: qwant
|
||||
disabled: true
|
||||
|
||||
# - name: library
|
||||
# engine: recoll
|
||||
@@ -2149,6 +2166,7 @@ engines:
|
||||
- name: yahoo news
|
||||
engine: yahoo_news
|
||||
shortcut: yhn
|
||||
inactive: true
|
||||
|
||||
- name: youtube
|
||||
shortcut: yt
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"BnP4vIuG.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/search.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen } from \"../toolkit.ts\";\nimport { getElement } from \"../util/getElement.ts\";\n\nconst searchForm: HTMLFormElement = getElement<HTMLFormElement>(\"search\");\nconst searchInput: HTMLInputElement = getElement<HTMLInputElement>(\"q\");\nconst searchReset: HTMLButtonElement = getElement<HTMLButtonElement>(\"clear_search\");\n\nconst isMobile: boolean = window.matchMedia(\"(max-width: 50em)\").matches;\nconst isResultsPage: boolean = document.querySelector(\"main\")?.id === \"main_results\";\n\nconst categoryButtons: HTMLButtonElement[] = Array.from(\n document.querySelectorAll<HTMLButtonElement>(\"#categories_container button.category\")\n);\n\nif (searchInput.value.length === 0) {\n searchReset.classList.add(\"empty\");\n}\n\n// focus search input on large screens\nif (!(isMobile || isResultsPage)) {\n searchInput.focus();\n}\n\n// On mobile, move cursor to the end of the input on focus\nif (isMobile) {\n listen(\"focus\", searchInput, () => {\n // Defer cursor move until the next frame to prevent a visual jump\n requestAnimationFrame(() => {\n const end = searchInput.value.length;\n searchInput.setSelectionRange(end, end);\n searchInput.scrollLeft = searchInput.scrollWidth;\n });\n });\n}\n\nlisten(\"input\", searchInput, () => {\n searchReset.classList.toggle(\"empty\", searchInput.value.length === 0);\n});\n\nlisten(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\n searchReset.classList.add(\"empty\");\n});\n\nfor (const button of categoryButtons) {\n listen(\"click\", button, (event: MouseEvent) => {\n if (event.shiftKey) {\n event.preventDefault();\n button.classList.toggle(\"selected\");\n return;\n }\n\n // deselect all other categories\n for (const categoryButton of categoryButtons) {\n categoryButton.classList.toggle(\"selected\", categoryButton === button);\n }\n });\n}\n\nif (document.querySelector(\"div.search_filters\")) {\n const safesearchElement = document.getElementById(\"safesearch\");\n if (safesearchElement) {\n listen(\"change\", safesearchElement, () => searchForm.submit());\n }\n\n const timeRangeElement = document.getElementById(\"time_range\");\n if (timeRangeElement) {\n listen(\"change\", timeRangeElement, () => searchForm.submit());\n }\n\n const languageElement = document.getElementById(\"language\");\n if (languageElement) {\n listen(\"change\", languageElement, () => searchForm.submit());\n }\n}\n\n// override searchForm submit event\nlisten(\"submit\", searchForm, (event: Event) => {\n event.preventDefault();\n\n if (categoryButtons.length > 0) {\n const searchCategories = getElement<HTMLInputElement>(\"selected-categories\");\n searchCategories.value = categoryButtons\n .filter((button) => button.classList.contains(\"selected\"))\n .map((button) => button.name.replace(\"category_\", \"\"))\n .join(\",\");\n }\n\n searchForm.submit();\n});\n"],"mappings":"yEAKA,IAAM,EAA8B,EAA4B,SAAS,CACnE,EAAgC,EAA6B,IAAI,CACjE,EAAiC,EAA8B,eAAe,CAE9E,EAAoB,OAAO,WAAW,oBAAoB,CAAC,QAC3D,EAAyB,SAAS,cAAc,OAAO,EAAE,KAAO,eAEhE,EAAuC,MAAM,KACjD,SAAS,iBAAoC,wCAAwC,CACtF,CAEG,EAAY,MAAM,SAAW,GAC/B,EAAY,UAAU,IAAI,QAAQ,CAI9B,GAAY,GAChB,EAAY,OAAO,CAIjB,GACF,EAAO,QAAS,MAAmB,CAEjC,0BAA4B,CAC1B,IAAM,EAAM,EAAY,MAAM,OAC9B,EAAY,kBAAkB,EAAK,EAAI,CACvC,EAAY,WAAa,EAAY,aACrC,EACF,CAGJ,EAAO,QAAS,MAAmB,CACjC,EAAY,UAAU,OAAO,QAAS,EAAY,MAAM,SAAW,EAAE,EACrE,CAEF,EAAO,QAAS,EAAc,GAAsB,CAClD,EAAM,gBAAgB,CACtB,EAAY,MAAQ,GACpB,EAAY,OAAO,CACnB,EAAY,UAAU,IAAI,QAAQ,EAClC,CAEF,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,EAAS,GAAsB,CAC7C,GAAI,EAAM,SAAU,CAClB,EAAM,gBAAgB,CACtB,EAAO,UAAU,OAAO,WAAW,CACnC,OAIF,IAAK,IAAM,KAAkB,EAC3B,EAAe,UAAU,OAAO,WAAY,IAAmB,EAAO,EAExE,CAGJ,GAAI,SAAS,cAAc,qBAAqB,CAAE,CAChD,IAAM,EAAoB,SAAS,eAAe,aAAa,CAC3D,GACF,EAAO,SAAU,MAAyB,EAAW,QAAQ,CAAC,CAGhE,IAAM,EAAmB,SAAS,eAAe,aAAa,CAC1D,GACF,EAAO,SAAU,MAAwB,EAAW,QAAQ,CAAC,CAG/D,IAAM,EAAkB,SAAS,eAAe,WAAW,CACvD,GACF,EAAO,SAAU,MAAuB,EAAW,QAAQ,CAAC,CAKhE,EAAO,SAAU,EAAa,GAAiB,CAG7C,GAFA,EAAM,gBAAgB,CAElB,EAAgB,OAAS,EAAG,CAC9B,IAAM,EAAmB,EAA6B,sBAAsB,CAC5E,EAAiB,MAAQ,EACtB,OAAQ,GAAW,EAAO,UAAU,SAAS,WAAW,CAAC,CACzD,IAAK,GAAW,EAAO,KAAK,QAAQ,YAAa,GAAG,CAAC,CACrD,KAAK,IAAI,CAGd,EAAW,QAAQ,EACnB"}
|
||||
{"version":3,"file":"BnP4vIuG.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/search.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { listen } from \"../toolkit.ts\";\nimport { getElement } from \"../util/getElement.ts\";\n\nconst searchForm: HTMLFormElement = getElement<HTMLFormElement>(\"search\");\nconst searchInput: HTMLInputElement = getElement<HTMLInputElement>(\"q\");\nconst searchReset: HTMLButtonElement = getElement<HTMLButtonElement>(\"clear_search\");\n\nconst isMobile: boolean = window.matchMedia(\"(max-width: 50em)\").matches;\nconst isResultsPage: boolean = document.querySelector(\"main\")?.id === \"main_results\";\n\nconst categoryButtons: HTMLButtonElement[] = Array.from(\n document.querySelectorAll<HTMLButtonElement>(\"#categories_container button.category\")\n);\n\nif (searchInput.value.length === 0) {\n searchReset.classList.add(\"empty\");\n}\n\n// focus search input on large screens\nif (!(isMobile || isResultsPage)) {\n searchInput.focus();\n}\n\n// On mobile, move cursor to the end of the input on focus\nif (isMobile) {\n listen(\"focus\", searchInput, () => {\n // Defer cursor move until the next frame to prevent a visual jump\n requestAnimationFrame(() => {\n const end = searchInput.value.length;\n searchInput.setSelectionRange(end, end);\n searchInput.scrollLeft = searchInput.scrollWidth;\n });\n });\n}\n\nlisten(\"input\", searchInput, () => {\n searchReset.classList.toggle(\"empty\", searchInput.value.length === 0);\n});\n\nlisten(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\n searchReset.classList.add(\"empty\");\n});\n\nfor (const button of categoryButtons) {\n listen(\"click\", button, (event: MouseEvent) => {\n if (event.shiftKey) {\n event.preventDefault();\n button.classList.toggle(\"selected\");\n return;\n }\n\n // deselect all other categories\n for (const categoryButton of categoryButtons) {\n categoryButton.classList.toggle(\"selected\", categoryButton === button);\n }\n });\n}\n\nif (document.querySelector(\"div.search_filters\")) {\n const safesearchElement = document.getElementById(\"safesearch\");\n if (safesearchElement) {\n listen(\"change\", safesearchElement, () => searchForm.submit());\n }\n\n const timeRangeElement = document.getElementById(\"time_range\");\n if (timeRangeElement) {\n listen(\"change\", timeRangeElement, () => searchForm.submit());\n }\n\n const languageElement = document.getElementById(\"language\");\n if (languageElement) {\n listen(\"change\", languageElement, () => searchForm.submit());\n }\n}\n\n// override searchForm submit event\nlisten(\"submit\", searchForm, (event: Event) => {\n event.preventDefault();\n\n if (categoryButtons.length > 0) {\n const searchCategories = getElement<HTMLInputElement>(\"selected-categories\");\n searchCategories.value = categoryButtons\n .filter((button) => button.classList.contains(\"selected\"))\n .map((button) => button.name.replace(\"category_\", \"\"))\n .join(\",\");\n }\n\n searchForm.submit();\n});\n"],"mappings":"yEAKA,IAAM,EAA8B,EAA4B,QAAQ,EAClE,EAAgC,EAA6B,GAAG,EAChE,EAAiC,EAA8B,cAAc,EAE7E,EAAoB,OAAO,WAAW,mBAAmB,EAAE,QAC3D,EAAyB,SAAS,cAAc,MAAM,GAAG,KAAO,eAEhE,EAAuC,MAAM,KACjD,SAAS,iBAAoC,uCAAuC,CACtF,EAEI,EAAY,MAAM,SAAW,GAC/B,EAAY,UAAU,IAAI,OAAO,EAI7B,GAAY,GAChB,EAAY,MAAM,EAIhB,GACF,EAAO,QAAS,MAAmB,CAEjC,0BAA4B,CAC1B,IAAM,EAAM,EAAY,MAAM,OAC9B,EAAY,kBAAkB,EAAK,CAAG,EACtC,EAAY,WAAa,EAAY,WACvC,CAAC,CACH,CAAC,EAGH,EAAO,QAAS,MAAmB,CACjC,EAAY,UAAU,OAAO,QAAS,EAAY,MAAM,SAAW,CAAC,CACtE,CAAC,EAED,EAAO,QAAS,EAAc,GAAsB,CAClD,EAAM,eAAe,EACrB,EAAY,MAAQ,GACpB,EAAY,MAAM,EAClB,EAAY,UAAU,IAAI,OAAO,CACnC,CAAC,EAED,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,EAAS,GAAsB,CAC7C,GAAI,EAAM,SAAU,CAClB,EAAM,eAAe,EACrB,EAAO,UAAU,OAAO,UAAU,EAClC,MACF,CAGA,IAAK,IAAM,KAAkB,EAC3B,EAAe,UAAU,OAAO,WAAY,IAAmB,CAAM,CAEzE,CAAC,EAGH,GAAI,SAAS,cAAc,oBAAoB,EAAG,CAChD,IAAM,EAAoB,SAAS,eAAe,YAAY,EAC1D,GACF,EAAO,SAAU,MAAyB,EAAW,OAAO,CAAC,EAG/D,IAAM,EAAmB,SAAS,eAAe,YAAY,EACzD,GACF,EAAO,SAAU,MAAwB,EAAW,OAAO,CAAC,EAG9D,IAAM,EAAkB,SAAS,eAAe,UAAU,EACtD,GACF,EAAO,SAAU,MAAuB,EAAW,OAAO,CAAC,CAE/D,CAGA,EAAO,SAAU,EAAa,GAAiB,CAG7C,GAFA,EAAM,eAAe,EAEjB,EAAgB,OAAS,EAAG,CAC9B,IAAM,EAAmB,EAA6B,qBAAqB,EAC3E,EAAiB,MAAQ,EACtB,OAAQ,GAAW,EAAO,UAAU,SAAS,UAAU,CAAC,EACxD,IAAK,GAAW,EAAO,KAAK,QAAQ,YAAa,EAAE,CAAC,EACpD,KAAK,GAAG,CACb,CAEA,EAAW,OAAO,CACpB,CAAC"}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"DH1EQbEY.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/assertElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntype AssertElement = <T>(element?: T | null) => asserts element is T;\nexport const assertElement: AssertElement = <T>(element?: T | null): asserts element is T => {\n if (!element) {\n throw new Error(\"DOM element not found\");\n }\n};\n"],"mappings":"AAGA,IAAa,EAAmC,GAA6C,CAC3F,GAAI,CAAC,EACH,MAAU,MAAM,wBAAwB"}
|
||||
{"version":3,"file":"DH1EQbEY.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/assertElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\ntype AssertElement = <T>(element?: T | null) => asserts element is T;\nexport const assertElement: AssertElement = <T>(element?: T | null): asserts element is T => {\n if (!element) {\n throw new Error(\"DOM element not found\");\n }\n};\n"],"mappings":"AAGA,IAAa,EAAmC,GAA6C,CAC3F,GAAI,CAAC,EACH,MAAU,MAAM,uBAAuB,CAE3C"}
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"DZidprJh.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/preferences.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { http, listen, settings } from \"../toolkit.ts\";\nimport { assertElement } from \"../util/assertElement.ts\";\n\nlet engineDescriptions: Record<string, [string, string]> | undefined;\n\nconst loadEngineDescriptions = async (): Promise<void> => {\n if (engineDescriptions) return;\n try {\n const res = await http(\"GET\", \"engine_descriptions.json\");\n engineDescriptions = await res.json();\n } catch (error) {\n console.error(\"Error fetching engineDescriptions:\", error);\n }\n if (!engineDescriptions) return;\n\n for (const [engine_name, [description, source]] of Object.entries(engineDescriptions)) {\n const elements = document.querySelectorAll<HTMLElement>(`[data-engine-name=\"${engine_name}\"] .engine-description`);\n const sourceText = ` (<i>${settings.translations?.Source}: ${source}</i>)`;\n\n for (const element of elements) {\n element.innerHTML = description + sourceText;\n }\n }\n};\n\nconst toggleEngines = (enable: boolean, engineToggles: NodeListOf<HTMLInputElement>): void => {\n for (const engineToggle of engineToggles) {\n // check if element visible, so that only engines of the current category are modified\n if (engineToggle.offsetParent) {\n engineToggle.checked = !enable;\n }\n }\n};\n\nconst engineElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\"[data-engine-name]\");\nfor (const engineElement of engineElements) {\n listen(\"mouseenter\", engineElement, loadEngineDescriptions);\n}\n\nconst engineToggles: NodeListOf<HTMLInputElement> = document.querySelectorAll<HTMLInputElement>(\n \"tbody input[type=checkbox][class~=checkbox-onoff]\"\n);\n\nconst enableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\".enable-all-engines\");\nfor (const engine of enableAllEngines) {\n listen(\"click\", engine, () => toggleEngines(true, engineToggles));\n}\n\nconst disableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\".disable-all-engines\");\nfor (const engine of disableAllEngines) {\n listen(\"click\", engine, () => toggleEngines(false, engineToggles));\n}\n\nlisten(\"click\", \"#copy-hash\", async function (this: HTMLElement) {\n const target = this.parentElement?.querySelector<HTMLPreElement>(\"pre\");\n assertElement(target);\n\n if (window.isSecureContext) {\n await navigator.clipboard.writeText(target.innerText);\n } else {\n const selection = window.getSelection();\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(target);\n selection.removeAllRanges();\n selection.addRange(range);\n document.execCommand(\"copy\");\n }\n }\n\n if (this.dataset.copiedText) {\n this.innerText = this.dataset.copiedText;\n }\n});\n"],"mappings":"4FAKA,IAAI,EAEE,EAAyB,SAA2B,CACpD,MACJ,IAAI,CAEF,EAAqB,MAAM,MADT,EAAK,MAAO,2BAA2B,EAC1B,MAAM,OAC9B,EAAO,CACd,QAAQ,MAAM,qCAAsC,EAAM,CAEvD,KAEL,IAAK,GAAM,CAAC,EAAa,CAAC,EAAa,MAAY,OAAO,QAAQ,EAAmB,CAAE,CACrF,IAAM,EAAW,SAAS,iBAA8B,sBAAsB,EAAY,wBAAwB,CAC5G,EAAa,QAAQ,EAAS,cAAc,OAAO,SAAS,EAAO,OAEzE,IAAK,IAAM,KAAW,EACpB,EAAQ,UAAY,EAAc,KAKlC,GAAiB,EAAiB,IAAsD,CAC5F,IAAK,IAAM,KAAgB,EAErB,EAAa,eACf,EAAa,QAAU,CAAC,IAKxB,EAA0C,SAAS,iBAA8B,qBAAqB,CAC5G,IAAK,IAAM,KAAiB,EAC1B,EAAO,aAAc,EAAe,EAAuB,CAG7D,IAAM,EAA8C,SAAS,iBAC3D,oDACD,CAEK,EAA4C,SAAS,iBAA8B,sBAAsB,CAC/G,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,MAAc,EAAc,GAAM,EAAc,CAAC,CAGnE,IAAM,EAA6C,SAAS,iBAA8B,uBAAuB,CACjH,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,MAAc,EAAc,GAAO,EAAc,CAAC,CAGpE,EAAO,QAAS,aAAc,gBAAmC,CAC/D,IAAM,EAAS,KAAK,eAAe,cAA8B,MAAM,CAGvE,GAFA,EAAc,EAAO,CAEjB,OAAO,gBACT,MAAM,UAAU,UAAU,UAAU,EAAO,UAAU,KAChD,CACL,IAAM,EAAY,OAAO,cAAc,CACvC,GAAI,EAAW,CACb,IAAM,EAAQ,SAAS,aAAa,CACpC,EAAM,mBAAmB,EAAO,CAChC,EAAU,iBAAiB,CAC3B,EAAU,SAAS,EAAM,CACzB,SAAS,YAAY,OAAO,EAI5B,KAAK,QAAQ,aACf,KAAK,UAAY,KAAK,QAAQ,aAEhC"}
|
||||
{"version":3,"file":"DZidprJh.min.js","names":[],"sources":["../../../../../client/simple/src/js/main/preferences.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { http, listen, settings } from \"../toolkit.ts\";\nimport { assertElement } from \"../util/assertElement.ts\";\n\nlet engineDescriptions: Record<string, [string, string]> | undefined;\n\nconst loadEngineDescriptions = async (): Promise<void> => {\n if (engineDescriptions) return;\n try {\n const res = await http(\"GET\", \"engine_descriptions.json\");\n engineDescriptions = await res.json();\n } catch (error) {\n console.error(\"Error fetching engineDescriptions:\", error);\n }\n if (!engineDescriptions) return;\n\n for (const [engine_name, [description, source]] of Object.entries(engineDescriptions)) {\n const elements = document.querySelectorAll<HTMLElement>(`[data-engine-name=\"${engine_name}\"] .engine-description`);\n const sourceText = ` (<i>${settings.translations?.Source}: ${source}</i>)`;\n\n for (const element of elements) {\n element.innerHTML = description + sourceText;\n }\n }\n};\n\nconst toggleEngines = (enable: boolean, engineToggles: NodeListOf<HTMLInputElement>): void => {\n for (const engineToggle of engineToggles) {\n // check if element visible, so that only engines of the current category are modified\n if (engineToggle.offsetParent) {\n engineToggle.checked = !enable;\n }\n }\n};\n\nconst engineElements: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\"[data-engine-name]\");\nfor (const engineElement of engineElements) {\n listen(\"mouseenter\", engineElement, loadEngineDescriptions);\n}\n\nconst engineToggles: NodeListOf<HTMLInputElement> = document.querySelectorAll<HTMLInputElement>(\n \"tbody input[type=checkbox][class~=checkbox-onoff]\"\n);\n\nconst enableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\".enable-all-engines\");\nfor (const engine of enableAllEngines) {\n listen(\"click\", engine, () => toggleEngines(true, engineToggles));\n}\n\nconst disableAllEngines: NodeListOf<HTMLElement> = document.querySelectorAll<HTMLElement>(\".disable-all-engines\");\nfor (const engine of disableAllEngines) {\n listen(\"click\", engine, () => toggleEngines(false, engineToggles));\n}\n\nlisten(\"click\", \"#copy-hash\", async function (this: HTMLElement) {\n const target = this.parentElement?.querySelector<HTMLPreElement>(\"pre\");\n assertElement(target);\n\n if (window.isSecureContext) {\n await navigator.clipboard.writeText(target.innerText);\n } else {\n const selection = window.getSelection();\n if (selection) {\n const range = document.createRange();\n range.selectNodeContents(target);\n selection.removeAllRanges();\n selection.addRange(range);\n document.execCommand(\"copy\");\n }\n }\n\n if (this.dataset.copiedText) {\n this.innerText = this.dataset.copiedText;\n }\n});\n"],"mappings":"4FAKA,IAAI,EAEE,EAAyB,SAA2B,CACpD,MACJ,IAAI,CAEF,EAAqB,MAAM,MADT,EAAK,MAAO,0BAA0B,GACzB,KAAK,CACtC,OAAS,EAAO,CACd,QAAQ,MAAM,qCAAsC,CAAK,CAC3D,CACK,KAEL,IAAK,GAAM,CAAC,EAAa,CAAC,EAAa,MAAY,OAAO,QAAQ,CAAkB,EAAG,CACrF,IAAM,EAAW,SAAS,iBAA8B,sBAAsB,EAAY,uBAAuB,EAC3G,EAAa,QAAQ,EAAS,cAAc,OAAO,SAAS,EAAO,OAEzE,IAAK,IAAM,KAAW,EACpB,EAAQ,UAAY,EAAc,CAEtC,CAVA,CAWF,EAEM,GAAiB,EAAiB,IAAsD,CAC5F,IAAK,IAAM,KAAgB,EAErB,EAAa,eACf,EAAa,QAAU,CAAC,EAG9B,EAEM,EAA0C,SAAS,iBAA8B,oBAAoB,EAC3G,IAAK,IAAM,KAAiB,EAC1B,EAAO,aAAc,EAAe,CAAsB,EAG5D,IAAM,EAA8C,SAAS,iBAC3D,mDACF,EAEM,EAA4C,SAAS,iBAA8B,qBAAqB,EAC9G,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,MAAc,EAAc,GAAM,CAAa,CAAC,EAGlE,IAAM,EAA6C,SAAS,iBAA8B,sBAAsB,EAChH,IAAK,IAAM,KAAU,EACnB,EAAO,QAAS,MAAc,EAAc,GAAO,CAAa,CAAC,EAGnE,EAAO,QAAS,aAAc,gBAAmC,CAC/D,IAAM,EAAS,KAAK,eAAe,cAA8B,KAAK,EAGtE,GAFA,EAAc,CAAM,EAEhB,OAAO,gBACT,MAAM,UAAU,UAAU,UAAU,EAAO,SAAS,MAC/C,CACL,IAAM,EAAY,OAAO,aAAa,EACtC,GAAI,EAAW,CACb,IAAM,EAAQ,SAAS,YAAY,EACnC,EAAM,mBAAmB,CAAM,EAC/B,EAAU,gBAAgB,EAC1B,EAAU,SAAS,CAAK,EACxB,SAAS,YAAY,MAAM,CAC7B,CACF,CAEI,KAAK,QAAQ,aACf,KAAK,UAAY,KAAK,QAAQ,WAElC,CAAC"}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"chlzpS6K.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/getElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { assertElement } from \"./assertElement.ts\";\n\ntype Options = {\n assert?: boolean;\n};\n\nexport function getElement<T>(id: string, options?: { assert: true }): T;\nexport function getElement<T>(id: string, options?: { assert: false }): T | null;\nexport function getElement<T>(id: string, options: Options = {}): T | null {\n options.assert ??= true;\n\n const element = document.getElementById(id) as T | null;\n\n if (options.assert) {\n assertElement(element);\n }\n\n return element;\n}\n"],"mappings":"sCAUA,SAAgB,EAAc,EAAY,EAAmB,EAAE,CAAY,CACzE,EAAQ,SAAW,GAEnB,IAAM,EAAU,SAAS,eAAe,EAAG,CAM3C,OAJI,EAAQ,QACV,EAAc,EAAQ,CAGjB"}
|
||||
{"version":3,"file":"chlzpS6K.min.js","names":[],"sources":["../../../../../client/simple/src/js/util/getElement.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\nimport { assertElement } from \"./assertElement.ts\";\n\ntype Options = {\n assert?: boolean;\n};\n\nexport function getElement<T>(id: string, options?: { assert: true }): T;\nexport function getElement<T>(id: string, options?: { assert: false }): T | null;\nexport function getElement<T>(id: string, options: Options = {}): T | null {\n options.assert ??= true;\n\n const element = document.getElementById(id) as T | null;\n\n if (options.assert) {\n assertElement(element);\n }\n\n return element;\n}\n"],"mappings":"sCAUA,SAAgB,EAAc,EAAY,EAAmB,CAAC,EAAa,CACzE,EAAQ,SAAW,GAEnB,IAAM,EAAU,SAAS,eAAe,CAAE,EAM1C,OAJI,EAAQ,QACV,EAAc,CAAO,EAGhB,CACT"}
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -7,9 +7,7 @@
|
||||
<title>SearXNG search: {{ q|e }}</title>
|
||||
<link>{{ url_for('search', _external=True) }}?q={{ q|e }}</link>
|
||||
<description>Search results for "{{ q|e }}" - SearXNG</description>
|
||||
<opensearch:totalResults>{{ number_of_results }}</opensearch:totalResults>
|
||||
<opensearch:startIndex>1</opensearch:startIndex>
|
||||
<opensearch:itemsPerPage>{{ number_of_results }}</opensearch:itemsPerPage>
|
||||
<atom:link rel="search" type="application/opensearchdescription+xml" href="{{ opensearch_url }}"/>
|
||||
<opensearch:Query role="request" searchTerms="{{ q|e }}" startPage="1" />
|
||||
{% if error_message %}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
<th class="checkbox-col">{{- _("Allow") -}}</th>{{- '' -}}
|
||||
<th class="name">{{- _("Engine name") -}}</th>{{- '' -}}
|
||||
<th class="shortcut">{{ _("!bang") -}}</th>{{- '' -}}
|
||||
<th>{{- _("Supports selected language") -}}</th>{{- '' -}}
|
||||
<th>{{- _("SafeSearch") -}}</th>{{- '' -}}
|
||||
<th>{{- _("Time range") -}}</th>{{- '' -}}
|
||||
<th>{{- _("Weight") }}</th>
|
||||
@@ -70,9 +69,6 @@
|
||||
<td class="shortcut">{{- '' -}}
|
||||
<span class="bang">{{ '!' + shortcuts[search_engine.name] }}</span>{{- '' -}}
|
||||
</td>{{- '' -}}
|
||||
<td>
|
||||
{{- checkbox(None, supports[search_engine.name]['supports_selected_language'], true) -}}
|
||||
</td>{{- '' -}}
|
||||
<td>
|
||||
{{- checkbox(None, supports[search_engine.name]['safesearch'], true) -}}
|
||||
</td>{{- '' -}}
|
||||
|
||||
@@ -26,10 +26,6 @@
|
||||
|
||||
<div id="sidebar">
|
||||
|
||||
{%- if number_of_results != '0' -%}
|
||||
<p id="result_count"><small>{{ _('Number of results') }}: {{ number_of_results }}</small></p>
|
||||
{%- endif -%}
|
||||
|
||||
{%- if infoboxes -%}
|
||||
<div id="infoboxes">
|
||||
<details open class="sidebar-collapsible">
|
||||
|
||||
Binary file not shown.
@@ -16,15 +16,15 @@
|
||||
# jestie <jestie@users.noreply.translate.codeberg.org>, 2025.
|
||||
# APoniatowski <aponiatowski@users.noreply.translate.codeberg.org>, 2025.
|
||||
# French <french@noreply.codeberg.org>, 2025.
|
||||
# return42 <return42@noreply.codeberg.org>, 2025.
|
||||
# return42 <return42@noreply.codeberg.org>, 2025, 2026.
|
||||
# Raithlin <raithlin@noreply.codeberg.org>, 2025.
|
||||
# grumpyoldtechie <grumpyoldtechie@noreply.codeberg.org>, 2025.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-03-24 18:43+0000\n"
|
||||
"PO-Revision-Date: 2025-10-22 02:09+0000\n"
|
||||
"POT-Creation-Date: 2026-05-21 19:19+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: af\n"
|
||||
"Language-Team: Afrikaans "
|
||||
@@ -181,7 +181,7 @@ msgid "Uptime"
|
||||
msgstr "bedryfstyd"
|
||||
|
||||
#. BRAND_CUSTOM_LINKS['ABOUT']
|
||||
#: searx/searxng.msg searx/templates/simple/base.html:46
|
||||
#: searx/searxng.msg searx/templates/simple/base.html:47
|
||||
msgid "About"
|
||||
msgstr "Aangaande"
|
||||
|
||||
@@ -771,10 +771,13 @@ msgid "Infinite scroll"
|
||||
msgstr "Oneindige blaai"
|
||||
|
||||
#: searx/plugins/infinite_scroll.py:26
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
"Automatically loads the next page when scrolling to bottom of the current"
|
||||
" page"
|
||||
msgstr ""
|
||||
"Laai outomaties die volgende bladsy wanneer na die onderkant van die "
|
||||
"huidige bladsy geblaai word"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
msgid "Open Access DOI rewrite"
|
||||
@@ -875,45 +878,45 @@ msgstr "Gaan na %(search_page)s."
|
||||
msgid "search page"
|
||||
msgstr "soekblad"
|
||||
|
||||
#: searx/templates/simple/base.html:50
|
||||
#: searx/templates/simple/base.html:51
|
||||
msgid "Donate"
|
||||
msgstr "Skenk"
|
||||
|
||||
#: searx/templates/simple/base.html:55 searx/templates/simple/base.html:57
|
||||
#: searx/templates/simple/base.html:56 searx/templates/simple/base.html:58
|
||||
#: searx/templates/simple/preferences.html:152
|
||||
msgid "Preferences"
|
||||
msgstr "Voorkeure"
|
||||
|
||||
#: searx/templates/simple/base.html:68
|
||||
#: searx/templates/simple/base.html:69
|
||||
msgid "Powered by"
|
||||
msgstr "Aangedryf deur"
|
||||
|
||||
#: searx/templates/simple/base.html:68
|
||||
#: searx/templates/simple/base.html:69
|
||||
msgid "a privacy-respecting, open metasearch engine"
|
||||
msgstr "'n oop metasoekenjin wat privaatheid respekteer"
|
||||
|
||||
#: searx/templates/simple/base.html:69
|
||||
#: searx/templates/simple/base.html:70
|
||||
#: searx/templates/simple/result_templates/packages.html:59
|
||||
msgid "Source code"
|
||||
msgstr "Bronkode"
|
||||
|
||||
#: searx/templates/simple/base.html:70
|
||||
#: searx/templates/simple/base.html:71
|
||||
msgid "Issue tracker"
|
||||
msgstr "Probleem soeker"
|
||||
|
||||
#: searx/templates/simple/base.html:71 searx/templates/simple/stats.html:17
|
||||
#: searx/templates/simple/base.html:72 searx/templates/simple/stats.html:17
|
||||
msgid "Engine stats"
|
||||
msgstr "Enjin statistieke"
|
||||
|
||||
#: searx/templates/simple/base.html:73
|
||||
#: searx/templates/simple/base.html:74
|
||||
msgid "Public instances"
|
||||
msgstr "Openbare instansies"
|
||||
|
||||
#: searx/templates/simple/base.html:76
|
||||
#: searx/templates/simple/base.html:77
|
||||
msgid "Privacy policy"
|
||||
msgstr "Privaatheidsbeleid"
|
||||
|
||||
#: searx/templates/simple/base.html:79
|
||||
#: searx/templates/simple/base.html:80
|
||||
msgid "Contact instance maintainer"
|
||||
msgstr "Kontak instansie onderhouer"
|
||||
|
||||
@@ -1083,12 +1086,12 @@ msgid "Result count"
|
||||
msgstr "Resultaattelling"
|
||||
|
||||
#: searx/templates/simple/elements/engines_msg.html:7
|
||||
#: searx/templates/simple/preferences/engines.html:31
|
||||
#: searx/templates/simple/preferences/engines.html:30
|
||||
#: searx/templates/simple/stats.html:27
|
||||
msgid "Response time"
|
||||
msgstr "Reaksietyd"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:35
|
||||
#: searx/templates/simple/preferences/engines.html:34
|
||||
#: searx/templates/simple/stats.html:28
|
||||
msgid "Reliability"
|
||||
msgstr "Betroubaarheid"
|
||||
@@ -1217,7 +1220,7 @@ msgstr "Outo-bespeur"
|
||||
#: searx/templates/simple/filters/safesearch.html:2
|
||||
#: searx/templates/simple/filters/safesearch.html:3
|
||||
#: searx/templates/simple/filters/safesearch.html:4
|
||||
#: searx/templates/simple/preferences/engines.html:27
|
||||
#: searx/templates/simple/preferences/engines.html:26
|
||||
#: searx/templates/simple/preferences/safesearch.html:2
|
||||
msgid "SafeSearch"
|
||||
msgstr "VeiligeSoek"
|
||||
@@ -1238,7 +1241,7 @@ msgid "None"
|
||||
msgstr "Geen"
|
||||
|
||||
#: searx/templates/simple/filters/time_range.html:1
|
||||
#: searx/templates/simple/preferences/engines.html:28
|
||||
#: searx/templates/simple/preferences/engines.html:27
|
||||
msgid "Time range"
|
||||
msgstr "Tydreeks"
|
||||
|
||||
@@ -1436,15 +1439,11 @@ msgstr "Deaktiveer alles"
|
||||
msgid "!bang"
|
||||
msgstr "!bang"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:26
|
||||
msgid "Supports selected language"
|
||||
msgstr "Ondersteun gekose taal"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:29
|
||||
#: searx/templates/simple/preferences/engines.html:28
|
||||
msgid "Weight"
|
||||
msgstr "Gewig"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:33
|
||||
#: searx/templates/simple/preferences/engines.html:32
|
||||
msgid "Max time"
|
||||
msgstr "Maks tyd"
|
||||
|
||||
@@ -2159,3 +2158,6 @@ msgstr "versteek video"
|
||||
#~ msgid "Submit a new issue on Github including the above information"
|
||||
#~ msgstr "Dien 'n nuwe probleem in op GitHub insluitend die bogenoemde inligting"
|
||||
|
||||
#~ msgid "Supports selected language"
|
||||
#~ msgstr "Ondersteun gekose taal"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -24,15 +24,15 @@
|
||||
# Rick1029 <rick1029@users.noreply.translate.codeberg.org>, 2025.
|
||||
# Yahya-Lando <yahya-lando@users.noreply.translate.codeberg.org>, 2025.
|
||||
# curtwheeler <curtwheeler@users.noreply.translate.codeberg.org>, 2025.
|
||||
# return42 <return42@noreply.codeberg.org>, 2025.
|
||||
# return42 <return42@noreply.codeberg.org>, 2025, 2026.
|
||||
# DZDevelopers <dzdevelopers@noreply.codeberg.org>, 2025.
|
||||
# youtherthyf <youtherthyf@noreply.codeberg.org>, 2025.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-03-24 18:43+0000\n"
|
||||
"PO-Revision-Date: 2025-10-22 02:09+0000\n"
|
||||
"POT-Creation-Date: 2026-05-21 19:19+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: ar\n"
|
||||
"Language-Team: Arabic "
|
||||
@@ -190,7 +190,7 @@ msgid "Uptime"
|
||||
msgstr "فترة التشغيل"
|
||||
|
||||
#. BRAND_CUSTOM_LINKS['ABOUT']
|
||||
#: searx/searxng.msg searx/templates/simple/base.html:46
|
||||
#: searx/searxng.msg searx/templates/simple/base.html:47
|
||||
msgid "About"
|
||||
msgstr "حَول"
|
||||
|
||||
@@ -377,12 +377,12 @@ msgstr "مطر غزير"
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Light sleet and thunder"
|
||||
msgstr ""
|
||||
msgstr "مطر خفيف مخلوط بثلج و رعد"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
msgid "Light sleet showers and thunder"
|
||||
msgstr ""
|
||||
msgstr "زخات مطر خفيفة مصحوبة بثلج ورعد"
|
||||
|
||||
#. WEATHER_CONDITIONS
|
||||
#: searx/searxng.msg
|
||||
@@ -741,11 +741,11 @@ msgstr "قم بتصفية نتائج .onion التي تظهر في القائم
|
||||
|
||||
#: searx/plugins/calculator.py:25
|
||||
msgid "Calculator"
|
||||
msgstr ""
|
||||
msgstr "الآلة الحاسبة"
|
||||
|
||||
#: searx/plugins/calculator.py:26
|
||||
msgid "Parses and solves mathematical expressions."
|
||||
msgstr ""
|
||||
msgstr "يقوم بتحليل وحل التعبيرات الرياضية."
|
||||
|
||||
#: searx/plugins/hash_plugin.py:33
|
||||
msgid "Hash plugin"
|
||||
@@ -781,7 +781,7 @@ msgstr "تمرير الصفحات بلا حدود"
|
||||
msgid ""
|
||||
"Automatically loads the next page when scrolling to bottom of the current"
|
||||
" page"
|
||||
msgstr ""
|
||||
msgstr "يحمل الصفحة التالية تلقائيًا عند التمرير إلى أسفل الصفحة الحالية"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
msgid "Open Access DOI rewrite"
|
||||
@@ -817,11 +817,11 @@ msgstr "وكيل المستخدم الخاص بك هو "
|
||||
|
||||
#: searx/plugins/time_zone.py:33
|
||||
msgid "Timezones plugin"
|
||||
msgstr ""
|
||||
msgstr "إضافة المناطق الزمنية"
|
||||
|
||||
#: searx/plugins/time_zone.py:34
|
||||
msgid "Display the current time on different time zones."
|
||||
msgstr ""
|
||||
msgstr "اعرض الوقت الحالي في مناطق زمنية مختلفة."
|
||||
|
||||
#: searx/plugins/tor_check.py:41
|
||||
msgid "Tor check plugin"
|
||||
@@ -883,45 +883,45 @@ msgstr "إذهب إلى %(search_page)s."
|
||||
msgid "search page"
|
||||
msgstr "صفحة البحث"
|
||||
|
||||
#: searx/templates/simple/base.html:50
|
||||
#: searx/templates/simple/base.html:51
|
||||
msgid "Donate"
|
||||
msgstr "تبرُّع"
|
||||
|
||||
#: searx/templates/simple/base.html:55 searx/templates/simple/base.html:57
|
||||
#: searx/templates/simple/base.html:56 searx/templates/simple/base.html:58
|
||||
#: searx/templates/simple/preferences.html:152
|
||||
msgid "Preferences"
|
||||
msgstr "التفضيلات"
|
||||
|
||||
#: searx/templates/simple/base.html:68
|
||||
#: searx/templates/simple/base.html:69
|
||||
msgid "Powered by"
|
||||
msgstr "مدعوم بواسطة"
|
||||
|
||||
#: searx/templates/simple/base.html:68
|
||||
#: searx/templates/simple/base.html:69
|
||||
msgid "a privacy-respecting, open metasearch engine"
|
||||
msgstr "الخصوصية ذو الاعتبار, محرك البحث عميق عُموميا"
|
||||
|
||||
#: searx/templates/simple/base.html:69
|
||||
#: searx/templates/simple/base.html:70
|
||||
#: searx/templates/simple/result_templates/packages.html:59
|
||||
msgid "Source code"
|
||||
msgstr "شيفرة مصدرية"
|
||||
|
||||
#: searx/templates/simple/base.html:70
|
||||
#: searx/templates/simple/base.html:71
|
||||
msgid "Issue tracker"
|
||||
msgstr "تعقب القضايا"
|
||||
|
||||
#: searx/templates/simple/base.html:71 searx/templates/simple/stats.html:17
|
||||
#: searx/templates/simple/base.html:72 searx/templates/simple/stats.html:17
|
||||
msgid "Engine stats"
|
||||
msgstr "إحصائيات المحرك"
|
||||
|
||||
#: searx/templates/simple/base.html:73
|
||||
#: searx/templates/simple/base.html:74
|
||||
msgid "Public instances"
|
||||
msgstr "نماذج الخوادم العمومية"
|
||||
|
||||
#: searx/templates/simple/base.html:76
|
||||
#: searx/templates/simple/base.html:77
|
||||
msgid "Privacy policy"
|
||||
msgstr "سياسة الخصوصية"
|
||||
|
||||
#: searx/templates/simple/base.html:79
|
||||
#: searx/templates/simple/base.html:80
|
||||
msgid "Contact instance maintainer"
|
||||
msgstr "اتصال بالمشرف المخدم النموذجي"
|
||||
|
||||
@@ -994,11 +994,11 @@ msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences.html:158
|
||||
msgid "Press save to copy these preferences to your browser."
|
||||
msgstr ""
|
||||
msgstr "اضغط على حفظ لنسخ هذه التفضيلات إلى متصفحك."
|
||||
|
||||
#: searx/templates/simple/preferences.html:159
|
||||
msgid "Click here to view your browser preferences instead:"
|
||||
msgstr ""
|
||||
msgstr "انقر هنا لعرض تفضيلات متصفحك بدلاً من ذلك:"
|
||||
|
||||
#: searx/templates/simple/preferences.html:169
|
||||
msgid "General"
|
||||
@@ -1089,12 +1089,12 @@ msgid "Result count"
|
||||
msgstr "نتيجة العد"
|
||||
|
||||
#: searx/templates/simple/elements/engines_msg.html:7
|
||||
#: searx/templates/simple/preferences/engines.html:31
|
||||
#: searx/templates/simple/preferences/engines.html:30
|
||||
#: searx/templates/simple/stats.html:27
|
||||
msgid "Response time"
|
||||
msgstr "مدة الإستجابة"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:35
|
||||
#: searx/templates/simple/preferences/engines.html:34
|
||||
#: searx/templates/simple/stats.html:28
|
||||
msgid "Reliability"
|
||||
msgstr "إمكانية الإشتغال"
|
||||
@@ -1164,7 +1164,7 @@ msgstr "مرادفات"
|
||||
|
||||
#: searx/templates/simple/answer/weather.html:19
|
||||
msgid "Feels Like"
|
||||
msgstr ""
|
||||
msgstr "درجة الحرارة ظاهريًا"
|
||||
|
||||
#: searx/templates/simple/elements/answers.html:2
|
||||
msgid "Answers"
|
||||
@@ -1223,7 +1223,7 @@ msgstr "الاكتشاف التلقائي"
|
||||
#: searx/templates/simple/filters/safesearch.html:2
|
||||
#: searx/templates/simple/filters/safesearch.html:3
|
||||
#: searx/templates/simple/filters/safesearch.html:4
|
||||
#: searx/templates/simple/preferences/engines.html:27
|
||||
#: searx/templates/simple/preferences/engines.html:26
|
||||
#: searx/templates/simple/preferences/safesearch.html:2
|
||||
msgid "SafeSearch"
|
||||
msgstr "البحث المؤمَّن"
|
||||
@@ -1244,7 +1244,7 @@ msgid "None"
|
||||
msgstr "لا شيء"
|
||||
|
||||
#: searx/templates/simple/filters/time_range.html:1
|
||||
#: searx/templates/simple/preferences/engines.html:28
|
||||
#: searx/templates/simple/preferences/engines.html:27
|
||||
msgid "Time range"
|
||||
msgstr "الفترة"
|
||||
|
||||
@@ -1302,7 +1302,7 @@ msgstr "قم بتغيير محرك البحث المستخدم في الإعدا
|
||||
|
||||
#: searx/templates/simple/messages/no_results.html:22
|
||||
msgid "Switch to another instance:"
|
||||
msgstr "قم بتبديل SearxNG إلى نسخة أخرى:"
|
||||
msgstr "قم بتبديل SearXNG إلى نسخة أخرى:"
|
||||
|
||||
#: searx/templates/simple/messages/no_results.html:24
|
||||
msgid "Search for another query or select another category."
|
||||
@@ -1427,6 +1427,8 @@ msgid ""
|
||||
"This tab does not exist in the user interface, but you can search with "
|
||||
"these engines via !bangs."
|
||||
msgstr ""
|
||||
"لا توجد علامة التبويب هذه في واجهة المستخدم، ولكن يمكنك البحث باستخدام "
|
||||
"هذه المحركات عبر !bangs."
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:15
|
||||
msgid "Enable all"
|
||||
@@ -1440,15 +1442,11 @@ msgstr "عطّل الكل"
|
||||
msgid "!bang"
|
||||
msgstr "!bang"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:26
|
||||
msgid "Supports selected language"
|
||||
msgstr "يدعم اللغة المختارة"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:29
|
||||
#: searx/templates/simple/preferences/engines.html:28
|
||||
msgid "Weight"
|
||||
msgstr "وَزن"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:33
|
||||
#: searx/templates/simple/preferences/engines.html:32
|
||||
msgid "Max time"
|
||||
msgstr "أقصى مدّة"
|
||||
|
||||
@@ -1507,7 +1505,7 @@ msgstr "وكيل بروكسي الصور"
|
||||
|
||||
#: searx/templates/simple/preferences/image_proxy.html:14
|
||||
msgid "Proxy image results through SearXNG"
|
||||
msgstr ""
|
||||
msgstr "تمرير نتائج البحث عن الصور عبر بروكسي SearXNG"
|
||||
|
||||
#: searx/templates/simple/preferences/language.html:24
|
||||
msgid "What language do you prefer for search?"
|
||||
@@ -1539,11 +1537,11 @@ msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/results_on_new_tab.html:2
|
||||
msgid "Results in new tabs"
|
||||
msgstr ""
|
||||
msgstr "النتائج في علامات تبويب جديدة"
|
||||
|
||||
#: searx/templates/simple/preferences/results_on_new_tab.html:14
|
||||
msgid "Open result links in new browser tabs"
|
||||
msgstr ""
|
||||
msgstr "افتح روابط النتائج في علامات تبويب جديدة في المتصفح"
|
||||
|
||||
#: searx/templates/simple/preferences/safesearch.html:20
|
||||
msgid "Filter content"
|
||||
@@ -2393,3 +2391,6 @@ msgstr "إخفاء الفيديو"
|
||||
#~ msgid "Submit a new issue on Github including the above information"
|
||||
#~ msgstr "قم بتقديم مشكلة جديدة على GitHub بالمعلومات الواردة أعلاه"
|
||||
|
||||
#~ msgid "Supports selected language"
|
||||
#~ msgstr "يدعم اللغة المختارة"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user