mirror of
https://github.com/searxng/searxng.git
synced 2026-10-30 02:16:29 +00:00
Compare commits
51
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
448ced4b18 | ||
|
|
c360868e5b | ||
|
|
b5ed73fcb6 | ||
|
|
28423d332d | ||
|
|
ef7bae9ddb | ||
|
|
cb74e7f810 | ||
|
|
54ca1d9cfb | ||
|
|
ef0ec03da0 | ||
|
|
629368e40c | ||
|
|
68647d0806 | ||
|
|
81371861f6 | ||
|
|
d47cb96bfb | ||
|
|
62366b05c0 | ||
|
|
1c10abe2d3 | ||
|
|
3afd949268 | ||
|
|
2a6fc07be3 | ||
|
|
decdfa6f7d | ||
|
|
8252c0bf6d | ||
|
|
47aa11475b | ||
|
|
0ce72dd2cc | ||
|
|
c6d7fe91d3 | ||
|
|
7847767832 | ||
|
|
d2209bfbb0 | ||
|
|
ca8e1582be | ||
|
|
243d3a9df2 | ||
|
|
ff8f5ddcc9 | ||
|
|
b00212a836 | ||
|
|
22c64b8d39 | ||
|
|
ad46ebd7d8 | ||
|
|
f4822b3fc4 | ||
|
|
9f042d2f67 | ||
|
|
815f58994a | ||
|
|
6a0ac6a391 | ||
|
|
bba4f64e8a | ||
|
|
619696aa6c | ||
|
|
2dc2b14628 | ||
|
|
6671d89bed | ||
|
|
d48c4b5554 | ||
|
|
44b98e6102 | ||
|
|
7a3e41d420 | ||
|
|
ce913b8934 | ||
|
|
19ffbcd306 | ||
|
|
e652ca7d29 | ||
|
|
26b90797e0 | ||
|
|
a5659a5364 | ||
|
|
a9d9900334 | ||
|
|
4e2c1ea7f4 | ||
|
|
f5035873ad | ||
|
|
c11cbda117 | ||
|
|
bad451b3da | ||
|
|
896ec8d3af |
@@ -83,7 +83,7 @@ jobs:
|
||||
run: make container.build
|
||||
|
||||
- name: Upload container image
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: container-image-${{ matrix.arch }}
|
||||
path: "/var/tmp/searxng-podman/*.tar"
|
||||
@@ -116,7 +116,7 @@ jobs:
|
||||
persist-credentials: "false"
|
||||
|
||||
- name: Download container image
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
pattern: container-image-${{ matrix.arch }}
|
||||
path: "/var/tmp/searxng-podman"
|
||||
@@ -160,7 +160,7 @@ jobs:
|
||||
persist-credentials: "false"
|
||||
|
||||
- name: Download container images
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
pattern: container-image-*
|
||||
path: "/var/tmp/searxng-podman"
|
||||
|
||||
@@ -67,7 +67,7 @@ jobs:
|
||||
python-version: "${{ env.PYTHON_VERSION }}"
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
|
||||
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
|
||||
with:
|
||||
node-version: "26"
|
||||
check-latest: "true"
|
||||
|
||||
Generated
+341
-341
File diff suppressed because it is too large
Load Diff
@@ -25,25 +25,25 @@
|
||||
"dependencies": {
|
||||
"ionicons": "^8.1.0",
|
||||
"normalize.css": "8.0.1",
|
||||
"ol": "^10.10.0",
|
||||
"ol": "^10.11.0",
|
||||
"swiped-events": "1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.5.14",
|
||||
"@types/node": "^26.6.2",
|
||||
"browserslist": "^4.28.8",
|
||||
"@biomejs/biome": "2.5.15",
|
||||
"@types/node": "^26.6.5",
|
||||
"browserslist": "^4.29.4",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
"edge.js": "^6.5.1",
|
||||
"less": "^4.9.0",
|
||||
"mathjs": "^15.2.0",
|
||||
"sharp": "~0.35.4",
|
||||
"sort-package-json": "^4.0.0",
|
||||
"stylelint": "^17.14.1",
|
||||
"sharp": "~0.35.5",
|
||||
"sort-package-json": "^4.1.0",
|
||||
"stylelint": "^17.16.0",
|
||||
"stylelint-config-standard-less": "^4.1.0",
|
||||
"stylelint-prettier": "^5.0.3",
|
||||
"svgo": "^4.1.0",
|
||||
"typescript": "~7.0.2",
|
||||
"vite": "^8.3.0",
|
||||
"vite": "^8.3.3",
|
||||
"vite-bundle-analyzer": "^1.3.9"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,67 +8,68 @@ export type KeyBindingLayout = "default" | "vim";
|
||||
type KeyBinding = {
|
||||
key: string;
|
||||
fun: (event: KeyboardEvent) => void;
|
||||
des: string;
|
||||
cat: string;
|
||||
des?: string;
|
||||
cat?: string;
|
||||
};
|
||||
|
||||
type HighlightResultElement = "down" | "up" | "visible" | "bottom" | "top";
|
||||
|
||||
/* common base for layouts */
|
||||
|
||||
const baseKeyBinding: Record<string, KeyBinding> = {
|
||||
Escape: {
|
||||
key: "ESC",
|
||||
fun: (event: KeyboardEvent) => removeFocus(event),
|
||||
des: "remove focus from the focused input",
|
||||
cat: "Control"
|
||||
des: settings.translations?.hotkeys_remove_focus,
|
||||
cat: settings.translations?.hotkeys_category_control
|
||||
},
|
||||
c: {
|
||||
key: "c",
|
||||
fun: () => copyURLToClipboard(),
|
||||
des: "copy url of the selected result to the clipboard",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_copy_url,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
h: {
|
||||
key: "h",
|
||||
fun: () => toggleHelp(keyBindings),
|
||||
des: "toggle help window",
|
||||
cat: "Other"
|
||||
des: settings.translations?.hotkeys_toggle_help,
|
||||
cat: settings.translations?.hotkeys_category_other
|
||||
},
|
||||
i: {
|
||||
key: "i",
|
||||
fun: () => searchInputFocus(),
|
||||
des: "focus on the search input",
|
||||
cat: "Control"
|
||||
des: settings.translations?.hotkeys_focus_search,
|
||||
cat: settings.translations?.hotkeys_category_control
|
||||
},
|
||||
n: {
|
||||
key: "n",
|
||||
fun: () => GoToNextPage(),
|
||||
des: "go to next page",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_next_page,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
o: {
|
||||
key: "o",
|
||||
fun: () => openResult(false),
|
||||
des: "open search result",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_open_result,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
p: {
|
||||
key: "p",
|
||||
fun: () => GoToPreviousPage(),
|
||||
des: "go to previous page",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_previous_page,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
r: {
|
||||
key: "r",
|
||||
fun: () => reloadPage(),
|
||||
des: "reload page from the server",
|
||||
cat: "Control"
|
||||
des: settings.translations?.hotkeys_reload_page,
|
||||
cat: settings.translations?.hotkeys_category_control
|
||||
},
|
||||
t: {
|
||||
key: "t",
|
||||
fun: () => openResult(true),
|
||||
des: "open the result in a new tab",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_open_new_tab,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,14 +79,14 @@ const keyBindingLayouts: Record<KeyBindingLayout, Record<string, KeyBinding>> =
|
||||
ArrowLeft: {
|
||||
key: "←",
|
||||
fun: () => highlightResult("up")(),
|
||||
des: "select previous search result",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_select_previous,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
ArrowRight: {
|
||||
key: "→",
|
||||
fun: () => highlightResult("down")(),
|
||||
des: "select next search result",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_select_next,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
...baseKeyBinding
|
||||
},
|
||||
@@ -95,56 +96,56 @@ const keyBindingLayouts: Record<KeyBindingLayout, Record<string, KeyBinding>> =
|
||||
b: {
|
||||
key: "b",
|
||||
fun: () => scrollPage(-window.innerHeight),
|
||||
des: "scroll one page up",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_page_up,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
d: {
|
||||
key: "d",
|
||||
fun: () => scrollPage(window.innerHeight / 2),
|
||||
des: "scroll half a page down",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_half_page_down,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
f: {
|
||||
key: "f",
|
||||
fun: () => scrollPage(window.innerHeight),
|
||||
des: "scroll one page down",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_page_down,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
g: {
|
||||
key: "g",
|
||||
fun: () => scrollPageTo(-document.body.scrollHeight, "top"),
|
||||
des: "scroll to the top of the page",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_scroll_top,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
j: {
|
||||
key: "j",
|
||||
fun: () => highlightResult("down")(),
|
||||
des: "select next search result",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_select_next,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
k: {
|
||||
key: "k",
|
||||
fun: () => highlightResult("up")(),
|
||||
des: "select previous search result",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_select_previous,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
u: {
|
||||
key: "u",
|
||||
fun: () => scrollPage(-window.innerHeight / 2),
|
||||
des: "scroll half a page up",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_half_page_up,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
v: {
|
||||
key: "v",
|
||||
fun: () => scrollPageTo(document.body.scrollHeight, "bottom"),
|
||||
des: "scroll to the bottom of the page",
|
||||
cat: "Navigation"
|
||||
des: settings.translations?.hotkeys_scroll_bottom,
|
||||
cat: settings.translations?.hotkeys_category_navigation
|
||||
},
|
||||
y: {
|
||||
key: "y",
|
||||
fun: () => copyURLToClipboard(),
|
||||
des: "copy url of the selected result to the clipboard",
|
||||
cat: "Results"
|
||||
des: settings.translations?.hotkeys_copy_url,
|
||||
cat: settings.translations?.hotkeys_category_results
|
||||
},
|
||||
...baseKeyBinding
|
||||
}
|
||||
@@ -344,6 +345,7 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin
|
||||
|
||||
for (const binding of Object.values(keyBindings)) {
|
||||
const { cat } = binding;
|
||||
if (!cat) continue;
|
||||
categories[cat] ??= [];
|
||||
categories[cat].push(binding);
|
||||
}
|
||||
@@ -352,8 +354,8 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin
|
||||
(a, b) => (categories[b]?.length ?? 0) - (categories[a]?.length ?? 0)
|
||||
);
|
||||
|
||||
let html = '<a href="#" class="close" aria-label="close" title="close">×</a>';
|
||||
html += "<h3>How to navigate SearXNG with hotkeys</h3>";
|
||||
let html = `<a href="#" class="close" aria-label="${settings.translations?.close}" title="${settings.translations?.close}">×</a>`;
|
||||
html += `<h3>${settings.translations?.hotkeys_navigation_title}</h3>`;
|
||||
html += "<table>";
|
||||
|
||||
for (const [i, categoryKey] of sortedCategoryKeys.entries()) {
|
||||
@@ -372,6 +374,7 @@ const initHelpContent = (divElement: HTMLElement, keyBindings: typeof baseKeyBin
|
||||
html += '<ul class="list-unstyled">';
|
||||
|
||||
for (const binding of bindings) {
|
||||
if (!binding.des) continue;
|
||||
html += `<li><kbd>${binding.key}</kbd> ${binding.des}</li>`;
|
||||
}
|
||||
|
||||
|
||||
@@ -473,6 +473,8 @@ article[data-vim-selected].category-social {
|
||||
& > a {
|
||||
position: relative;
|
||||
outline: none;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Read the documentation before using the `docker-compose.yml` file:
|
||||
# https://docs.searxng.org/admin/installation-docker.html
|
||||
#
|
||||
# Additional ENVs:
|
||||
# Additional variables:
|
||||
# https://docs.searxng.org/admin/settings/settings_general.html#settings-general
|
||||
# https://docs.searxng.org/admin/settings/settings_server.html#settings-server
|
||||
|
||||
|
||||
@@ -1,4 +1,29 @@
|
||||
FROM localhost/searxng/searxng:builder AS builder
|
||||
FROM docker.io/searxng/base:searxng-builder AS builder
|
||||
|
||||
COPY ./requirements.txt ./requirements-server.txt ./
|
||||
|
||||
ENV UV_NO_MANAGED_PYTHON="true"
|
||||
|
||||
RUN --mount=type=cache,id=uv,target=/root/.cache/uv set -eux -o pipefail; \
|
||||
uv venv; \
|
||||
uv pip install --requirements ./requirements.txt --requirements ./requirements-server.txt; \
|
||||
uv cache prune --ci; \
|
||||
find ./.venv/lib/ -type f -exec strip --strip-unneeded {} + || true; \
|
||||
find ./.venv/lib/ -type d -name "__pycache__" -exec rm -rf {} +; \
|
||||
find ./.venv/lib/ -type f -name "*.pyc" -delete; \
|
||||
python -m compileall -q -f -j 0 --invalidation-mode=unchecked-hash ./.venv/lib/
|
||||
|
||||
COPY --exclude=./searx/version_frozen.py ./searx/ ./searx/
|
||||
|
||||
RUN set -eux -o pipefail; \
|
||||
python -m compileall -q -f -j 0 --invalidation-mode=unchecked-hash ./searx/; \
|
||||
find ./searx/static/ -type f \
|
||||
\( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" \) \
|
||||
-exec gzip -9 -k {} + \
|
||||
-exec brotli -9 -k {} + \
|
||||
-exec gzip --test {}.gz + \
|
||||
-exec brotli --test {}.br +
|
||||
|
||||
FROM docker.io/searxng/base:searxng AS dist
|
||||
|
||||
COPY --chown=977:977 --from=builder /usr/local/searxng/.venv/ ./.venv/
|
||||
@@ -21,6 +46,8 @@ LABEL org.opencontainers.image.created="$CREATED" \
|
||||
org.opencontainers.image.url="https://searxng.org" \
|
||||
org.opencontainers.image.version="$VERSION"
|
||||
|
||||
# Extended from:
|
||||
# https://codeberg.org/searxng/base/src/branch/main/Dockerfile
|
||||
ENV __SEARXNG_VERSION="$VERSION" \
|
||||
__SEARXNG_SETTINGS_PATH="$__SEARXNG_CONFIG_PATH/settings.yml" \
|
||||
GRANIAN_PROCESS_NAME="searxng" \
|
||||
@@ -32,7 +59,6 @@ ENV __SEARXNG_VERSION="$VERSION" \
|
||||
GRANIAN_WORKERS_KILL_TIMEOUT="30s" \
|
||||
GRANIAN_BLOCKING_THREADS_IDLE_TIMEOUT="5m"
|
||||
|
||||
# "*_PATH" ENVs are defined in base images
|
||||
VOLUME $__SEARXNG_CONFIG_PATH
|
||||
VOLUME $__SEARXNG_DATA_PATH
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
FROM docker.io/searxng/base:searxng-builder AS builder
|
||||
|
||||
COPY ./requirements.txt ./requirements-server.txt ./
|
||||
|
||||
ENV UV_NO_MANAGED_PYTHON="true"
|
||||
|
||||
RUN --mount=type=cache,id=uv,target=/root/.cache/uv set -eux -o pipefail; \
|
||||
uv venv; \
|
||||
uv pip install --requirements ./requirements.txt --requirements ./requirements-server.txt; \
|
||||
uv cache prune --ci; \
|
||||
find ./.venv/lib/ -type f -exec strip --strip-unneeded {} + || true; \
|
||||
find ./.venv/lib/ -type d -name "__pycache__" -exec rm -rf {} +; \
|
||||
find ./.venv/lib/ -type f -name "*.pyc" -delete; \
|
||||
python -m compileall -q -f -j 0 --invalidation-mode=unchecked-hash ./.venv/lib/
|
||||
|
||||
COPY --exclude=./searx/version_frozen.py ./searx/ ./searx/
|
||||
|
||||
RUN set -eux -o pipefail; \
|
||||
python -m compileall -q -f -j 0 --invalidation-mode=unchecked-hash ./searx/; \
|
||||
find ./searx/static/ -type f \
|
||||
\( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" \) \
|
||||
-exec gzip -9 -k {} + \
|
||||
-exec brotli -9 -k {} + \
|
||||
-exec gzip --test {}.gz + \
|
||||
-exec brotli --test {}.br +
|
||||
@@ -18,7 +18,7 @@ services:
|
||||
valkey:
|
||||
container_name: searxng-valkey
|
||||
image: docker.io/valkey/valkey:9-alpine
|
||||
command: valkey-server --save 30 1 --loglevel warning
|
||||
command: valkey-server --save 300 1 --save 60 1000 --loglevel warning
|
||||
restart: always
|
||||
volumes:
|
||||
- valkey-data:/data/
|
||||
|
||||
@@ -13,7 +13,7 @@ check_file() {
|
||||
!!! "$target" is not a valid file, exiting...
|
||||
!!!
|
||||
EOF
|
||||
exit 127
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ check_directory() {
|
||||
!!! "$target" is not a valid directory, exiting...
|
||||
!!!
|
||||
EOF
|
||||
exit 127
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -283,12 +283,12 @@ container images are not officially supported):
|
||||
$ make container
|
||||
|
||||
$ docker images
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
localhost/searxng/searxng 2026.6.19-93f66bfb4 ... 265 MB
|
||||
localhost/searxng/searxng latest ... 265 MB
|
||||
localhost/searxng/searxng builder ... 687 MB
|
||||
docker.io/searxng/base searxng-builder ... 565 MB
|
||||
docker.io/searxng/base searxng ... 143 MB
|
||||
REPOSITORY TAG IMAGE ID SIZE
|
||||
localhost/searxng/searxng latest ... 271 MB
|
||||
localhost/searxng/searxng 2026.10.17-* ... 271 MB
|
||||
<none> <none> ... 677 MB
|
||||
docker.io/searxng/base searxng ... 144 MB
|
||||
docker.io/searxng/base searxng-builder ... 550 MB
|
||||
|
||||
Migrate from ``searxng-docker``
|
||||
===============================
|
||||
|
||||
@@ -48,7 +48,7 @@ PATH="${PY_ENV}/bin:${REPO_ROOT}/node_modules/.bin:${GOROOT}/bin:${GOPATH}/bin:$
|
||||
|
||||
PYOBJECTS="searx"
|
||||
PY_SETUP_EXTRAS='[test]'
|
||||
GECKODRIVER_VERSION="v0.37.0"
|
||||
GECKODRIVER_VERSION="v0.37.1"
|
||||
# SPHINXOPTS=
|
||||
BLACK_OPTIONS=("--target-version" "py311" "--line-length" "120" "--skip-string-normalization")
|
||||
BLACK_TARGETS=("--exclude" "(searx/static|searx/languages.py)" "--include" 'searxng.msg|\.pyi?$' "searx" "searxng_extra" "tests")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
mock==5.2.0
|
||||
nose2[coverage_plugin]==0.16.0
|
||||
cov-core==1.15.0
|
||||
black==26.5.1
|
||||
pylint==4.0.8
|
||||
black==26.10.1
|
||||
pylint==4.1.3
|
||||
splinter==0.21.0
|
||||
selenium==4.49.0
|
||||
selenium==4.51.0
|
||||
Sphinx==8.2.3;python_version <= "3.11"
|
||||
Sphinx==9.1.0; python_version > "3.11"
|
||||
sphinx-issues==6.0.0
|
||||
@@ -18,11 +18,11 @@ myst-parser==5.0.0
|
||||
linuxdoc==20260504
|
||||
aiounittest==1.5.0
|
||||
yamllint==1.38.0
|
||||
wlc==2.2.0
|
||||
wlc==2.2.1
|
||||
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.8.3
|
||||
basedpyright==1.40.1
|
||||
granian[reload]==2.8.5
|
||||
basedpyright==1.40.2
|
||||
types-lxml==2026.2.16
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
granian==2.8.3
|
||||
granian[pname]==2.8.3
|
||||
granian==2.8.5
|
||||
granian[pname]==2.8.5
|
||||
|
||||
+5
-5
@@ -1,17 +1,17 @@
|
||||
certifi==2026.7.22
|
||||
certifi==2026.10.23
|
||||
babel==2.18.0
|
||||
flask-babel==4.0.0
|
||||
flask==3.1.3
|
||||
jinja2==3.1.6
|
||||
lxml==6.1.3
|
||||
pygments==2.21.0
|
||||
python-dateutil==2.9.0.post0
|
||||
python-dateutil==3.0.0
|
||||
pyyaml==6.0.3
|
||||
curl_cffi==0.16.3
|
||||
curl_cffi==0.17.0
|
||||
valkey==6.1.1
|
||||
markdown-it-py==4.2.0
|
||||
msgspec==0.21.1
|
||||
typer==0.27.2
|
||||
msgspec==0.22.0
|
||||
typer==0.27.3
|
||||
isodate==0.7.2
|
||||
whitenoise==6.12.0
|
||||
typing-extensions==4.16.0
|
||||
|
||||
@@ -28,19 +28,19 @@ if t.TYPE_CHECKING:
|
||||
from searx.extended_types import SXNG_Response
|
||||
|
||||
|
||||
def update_kwargs(**kwargs) -> None: # type: ignore
|
||||
def update_kwargs(kwargs) -> None: # type: ignore
|
||||
if 'timeout' not in kwargs:
|
||||
kwargs['timeout'] = settings['outgoing']['request_timeout']
|
||||
kwargs['raise_for_httperror'] = True
|
||||
|
||||
|
||||
def get(*args, **kwargs) -> "SXNG_Response": # type: ignore
|
||||
update_kwargs(**kwargs) # pyright: ignore[reportUnknownArgumentType]
|
||||
update_kwargs(kwargs)
|
||||
return http_get(*args, **kwargs) # pyright: ignore[reportUnknownArgumentType]
|
||||
|
||||
|
||||
def post(*args, **kwargs) -> "SXNG_Response": # type: ignore
|
||||
update_kwargs(**kwargs) # pyright: ignore[reportUnknownArgumentType]
|
||||
update_kwargs(kwargs)
|
||||
return http_post(*args, **kwargs) # pyright: ignore[reportUnknownArgumentType]
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+255
-27
File diff suppressed because it is too large
Load Diff
+4095
-5178
File diff suppressed because it is too large
Load Diff
@@ -93,7 +93,7 @@ class TrackerPatternsDB:
|
||||
continue
|
||||
|
||||
if resp.status_code != 200:
|
||||
log.warning(f"TRACKER_PATTERNS: ClearURL ignore HTTP {resp.status_code} {url}")
|
||||
log.warning("TRACKER_PATTERNS: ClearURL ignore HTTP %s %s", resp.status_code, url)
|
||||
continue
|
||||
|
||||
break
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
],
|
||||
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
|
||||
"versions": [
|
||||
"154.0",
|
||||
"153.0"
|
||||
"157.0",
|
||||
"156.0"
|
||||
]
|
||||
}
|
||||
+268
-513
File diff suppressed because it is too large
Load Diff
+13
-1818
File diff suppressed because it is too large
Load Diff
+14
-12
@@ -115,26 +115,26 @@ def load_engine(engine_data: dict[str, t.Any]) -> "Engine | types.ModuleType | N
|
||||
logger.error('An engine does not have a "name" field')
|
||||
return None
|
||||
if '_' in engine_name:
|
||||
logger.error('Engine name contains underscore: "{}"'.format(engine_name))
|
||||
logger.error('Engine name contains underscore: "%s"', engine_name)
|
||||
return None
|
||||
|
||||
if engine_name.lower() != engine_name:
|
||||
logger.warning('Engine name is not lowercase: "{}", converting to lowercase'.format(engine_name))
|
||||
logger.warning('Engine name is not lowercase: "%s", converting to lowercase', engine_name)
|
||||
engine_name = engine_name.lower()
|
||||
engine_data['name'] = engine_name
|
||||
|
||||
# load_module
|
||||
module_name = engine_data.get('engine')
|
||||
if module_name is None:
|
||||
logger.error('The "engine" field is missing for the engine named "{}"'.format(engine_name))
|
||||
logger.error('The "engine" field is missing for the engine named "%s"', engine_name)
|
||||
return None
|
||||
try:
|
||||
engine = load_module(module_name + '.py', ENGINE_DIR)
|
||||
except (SyntaxError, KeyboardInterrupt, SystemExit, SystemError, ImportError, RuntimeError):
|
||||
logger.exception('Fatal exception in engine "{}"'.format(module_name))
|
||||
logger.exception('Fatal exception in engine "%s"', module_name)
|
||||
sys.exit(1)
|
||||
except BaseException:
|
||||
logger.exception('Cannot load engine "{}"'.format(module_name))
|
||||
logger.exception('Cannot load engine "%s"', module_name)
|
||||
return None
|
||||
|
||||
check_engine_module(engine)
|
||||
@@ -247,7 +247,7 @@ def is_missing_required_attributes(engine: "Engine | types.ModuleType"):
|
||||
missing = False
|
||||
for engine_attr in dir(engine):
|
||||
if not engine_attr.startswith('_') and getattr(engine, engine_attr) is None:
|
||||
logger.error('Missing engine config attribute: "{0}.{1}"'.format(engine.name, engine_attr))
|
||||
logger.error('Missing engine config attribute: "%s.%s"', engine.name, engine_attr)
|
||||
missing = True
|
||||
return missing
|
||||
|
||||
@@ -277,12 +277,12 @@ def call_engine_setup(engine: "Engine | types.ModuleType", engine_data: dict[str
|
||||
if setup_func is None:
|
||||
setup_ok = True
|
||||
elif not callable(setup_func):
|
||||
logger.error(f"engine's setup method isn't a callable (is of type: {type(setup_func)})")
|
||||
logger.error("engine's setup method isn't a callable (is of type: %s)", type(setup_func))
|
||||
else:
|
||||
try:
|
||||
setup_ok = engine.setup(engine_data)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
logger.exception(f"(PID {os.getpid()}) {engine.name}: engine SETUP failed, exception: {e}")
|
||||
logger.exception("(PID %s) %s: engine SETUP failed, exception: %s", os.getpid(), engine.name, e)
|
||||
setup_ok = False
|
||||
|
||||
# The evaluation of the return value is analogous to Engine.init
|
||||
@@ -290,18 +290,18 @@ def call_engine_setup(engine: "Engine | types.ModuleType", engine_data: dict[str
|
||||
setup_ok = True
|
||||
|
||||
if not setup_ok:
|
||||
logger.error(f"(PID {os.getpid()}) {engine.name}: engine setup was not successful")
|
||||
logger.error("(PID %s) %s: engine setup was not successful", os.getpid(), engine.name)
|
||||
return setup_ok
|
||||
|
||||
|
||||
def register_engine(engine: "Engine | types.ModuleType"):
|
||||
if engine.name in engines:
|
||||
logger.error('Engine config error: ambiguous name: {0}'.format(engine.name))
|
||||
logger.error('Engine config error: ambiguous name: %s', engine.name)
|
||||
sys.exit(1)
|
||||
engines[engine.name] = engine
|
||||
|
||||
if engine.shortcut in engine_shortcuts:
|
||||
logger.error('Engine config error: ambiguous shortcut: {0}'.format(engine.shortcut))
|
||||
logger.error('Engine config error: ambiguous shortcut: %s', engine.shortcut)
|
||||
sys.exit(1)
|
||||
engine_shortcuts[engine.shortcut] = engine.name
|
||||
|
||||
@@ -327,7 +327,9 @@ def load_engines(engine_list: list[dict[str, t.Any]]):
|
||||
# if an engine can't be loaded (if for example the engine is missing
|
||||
# tor or some other requirements) its set to inactive!
|
||||
logger.error(
|
||||
f"(PID {os.getpid()}) {engine_data.get('name', '???')}: can't register engine (loading engine failed)"
|
||||
"(PID %s) %s: can't register engine (loading engine failed)",
|
||||
os.getpid(),
|
||||
engine_data.get("name", "???"),
|
||||
)
|
||||
engine_data["inactive"] = True
|
||||
return engines
|
||||
|
||||
@@ -37,8 +37,7 @@ def obtain_token():
|
||||
)
|
||||
token['value'] = loads(actual_token.text)['authInfo']['access_token']
|
||||
token['last_updated'] = update_time
|
||||
# pylint: disable=bare-except
|
||||
except:
|
||||
except: # pylint: disable=bare-except
|
||||
pass
|
||||
return token
|
||||
|
||||
|
||||
+102
-21
@@ -118,6 +118,7 @@ Implementations
|
||||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import typing as t
|
||||
from collections.abc import Callable
|
||||
from urllib.parse import urlencode
|
||||
@@ -129,7 +130,14 @@ from searx.enginelib.traits import EngineTraits
|
||||
from searx.exceptions import SearxEngineResponseException
|
||||
from searx.result_types import EngineResults, MainResult, Video
|
||||
from searx.result_types.image import Image
|
||||
from searx.utils import html_to_text, js_obj_str_to_json_str, js_obj_str_to_python
|
||||
from searx.utils import (
|
||||
html_to_text,
|
||||
js_find_matching_bracket,
|
||||
js_obj_str_to_json_str,
|
||||
js_obj_str_to_python,
|
||||
js_split_args,
|
||||
js_find_variable_positions,
|
||||
)
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from searx.extended_types import SXNG_Response
|
||||
@@ -188,6 +196,16 @@ time_range_map: dict[str, str] = {
|
||||
"year": "py",
|
||||
}
|
||||
|
||||
IIFE_RE = re.compile(
|
||||
r"""
|
||||
\(function\s*\( # (function(
|
||||
(?P<params>[^)]*) # formal parameters
|
||||
\)\s*\{\s*return\s* # ){ return
|
||||
(?P<body>\{) # the object literal starts
|
||||
""",
|
||||
re.VERBOSE | re.DOTALL,
|
||||
)
|
||||
|
||||
|
||||
def request(query: str, params: dict[str, t.Any]) -> None:
|
||||
|
||||
@@ -207,12 +225,10 @@ def request(query: str, params: dict[str, t.Any]) -> None:
|
||||
if brave_category == "goggles":
|
||||
args["goggles_id"] = Goggles
|
||||
|
||||
params["headers"]["Accept-Encoding"] = "gzip, deflate"
|
||||
params["url"] = f"{base_url}{brave_category}?{urlencode(args)}"
|
||||
logger.debug("url %s", params["url"])
|
||||
|
||||
# set properties in the cookies
|
||||
|
||||
params["cookies"]["safesearch"] = safesearch_map.get(params["safesearch"], "off")
|
||||
# the useLocation is IP based, we use cookie "country" for the region
|
||||
params["cookies"]["useLocation"] = "0"
|
||||
@@ -235,25 +251,90 @@ def _extract_published_date(published_date_raw: str | None):
|
||||
return None
|
||||
|
||||
|
||||
def extract_iife_object(data_src: str, match: re.Match[str]) -> tuple[str, int]:
|
||||
"""
|
||||
Extract and substitute the object literal from a JavaScript IIFE.
|
||||
Returns the transformed object literal and the position immediately after the IIFE call.
|
||||
"""
|
||||
body_start = match.start("body")
|
||||
body_end = js_find_matching_bracket(data_src, body_start, "{", "}")
|
||||
obj_str = data_src[body_start : body_end + 1]
|
||||
|
||||
# 1. Locate the argument call execution signature block: ...)(arg1, arg2)
|
||||
call_start = data_src.find("(", body_end)
|
||||
if call_start == -1:
|
||||
raise ValueError("IIFE missing call arguments")
|
||||
call_end = js_find_matching_bracket(data_src, call_start, "(", ")")
|
||||
|
||||
# 2. map arguments
|
||||
args = js_split_args(data_src[call_start + 1 : call_end])
|
||||
params = [p.strip() for p in match["params"].split(",") if p.strip()]
|
||||
mapping = dict(zip(params, args))
|
||||
|
||||
# 3. substitute idents
|
||||
variables = js_find_variable_positions(obj_str)
|
||||
for variable_name, pos in reversed(variables):
|
||||
if variable_name in mapping:
|
||||
value = mapping[variable_name]
|
||||
obj_str = obj_str[:pos] + value + obj_str[pos + len(variable_name) :]
|
||||
|
||||
return obj_str, call_end + 1
|
||||
|
||||
|
||||
def extract_json_data(text: str) -> dict[str, t.Any]:
|
||||
# Example script source containing the data:
|
||||
#
|
||||
# kit.start(app, element, {
|
||||
# node_ids: [0, 19],
|
||||
# data: [{type:"data",data: .... ["q","goggles_id"],route:1,url:1}}]
|
||||
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
# form: null,
|
||||
# error: null
|
||||
# });
|
||||
start = text.index("data: [{")
|
||||
newline = text.index("\n", start)
|
||||
end = text.rindex("}}]", start, newline)
|
||||
js_obj_str = "{" + text[start:end] + "}}]}"
|
||||
# js_obj_str = js_obj_str.replace("\xa0", "") # remove ASCII for
|
||||
# js_obj_str = js_obj_str.replace(r"\u003C", "<").replace(r"\u003c", "<") # fix broken HTML tags in strings
|
||||
json_str = js_obj_str_to_json_str(js_obj_str)
|
||||
data: dict[str, t.Any] = json.loads(json_str)
|
||||
return data
|
||||
"""
|
||||
Extract the SvelteKit data payload that Brave embeds in the page.
|
||||
|
||||
Handles:
|
||||
- plain-object form
|
||||
- pure IIFE form
|
||||
- mixed form (IIFE + plain object) that appears on some news pages
|
||||
"""
|
||||
marker = "data: ["
|
||||
start = text.find(marker)
|
||||
if start == -1:
|
||||
raise ValueError("Brave data payload not found (no 'data: [')")
|
||||
|
||||
array_start = start + len(marker) - 1 # Points directly at '['
|
||||
array_end = js_find_matching_bracket(text, array_start, "[", "]")
|
||||
data_src = text[array_start + 1 : array_end]
|
||||
|
||||
objects: list[str] = []
|
||||
pos = 0
|
||||
n = len(data_src)
|
||||
|
||||
while pos < n:
|
||||
# Move past whitespace and commas safely
|
||||
while pos < n and data_src[pos] in " \t\n\r,":
|
||||
pos += 1
|
||||
if pos >= n:
|
||||
break
|
||||
|
||||
# Case 1: IIFE Object Signature Matches
|
||||
if m := IIFE_RE.match(data_src, pos):
|
||||
obj_str, next_pos = extract_iife_object(data_src, m)
|
||||
objects.append(obj_str)
|
||||
pos = next_pos
|
||||
# Brave sometimes emits an extra ')' after the IIFE call
|
||||
while pos < n and data_src[pos] in " \t\n\r)":
|
||||
pos += 1
|
||||
continue
|
||||
|
||||
# Case 2: Standard raw plain JSON mapping block {type:"data", ...}
|
||||
if data_src[pos] == "{":
|
||||
obj_end = js_find_matching_bracket(data_src, pos, "{", "}")
|
||||
objects.append(data_src[pos : obj_end + 1])
|
||||
pos = obj_end + 1
|
||||
continue
|
||||
|
||||
raise ValueError(f"unexpected token in data array at offset {pos}: {data_src[pos : pos + 40]!r}")
|
||||
|
||||
if not objects:
|
||||
raise ValueError("no data objects found inside Brave payload")
|
||||
|
||||
combined = '{"data":[' + ",".join(objects) + "]}"
|
||||
json_str = js_obj_str_to_json_str(combined)
|
||||
return json.loads(json_str)
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
|
||||
@@ -51,6 +51,7 @@ api_key: str = ""
|
||||
categories = ["general", "web"]
|
||||
paging = True
|
||||
safesearch = True
|
||||
safesearch_map = {2: "strict", 1: "moderate", 0: "off"}
|
||||
time_range_support = True
|
||||
|
||||
results_per_page: int = 20
|
||||
@@ -84,9 +85,8 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
if params["time_range"]:
|
||||
search_args["time_range"] = time_range_map.get(params["time_range"])
|
||||
|
||||
# Apply SafeSearch if enabled
|
||||
if params["safesearch"]:
|
||||
search_args["safesearch"] = "strict"
|
||||
# Apply SafeSearch
|
||||
search_args["safesearch"] = safesearch_map.get(params["safesearch"], "off")
|
||||
|
||||
params["url"] = f"{base_url}?{urlencode(search_args)}"
|
||||
params["headers"]["X-Subscription-Token"] = api_key
|
||||
|
||||
@@ -169,7 +169,7 @@ def _get_results_from_process(res: EngineResults, cmd, pageno):
|
||||
for raw_result in raw_results:
|
||||
result = __parse_single_result(raw_result)
|
||||
if result is None:
|
||||
_command_logger.debug('skipped result:', raw_result)
|
||||
_command_logger.debug('skipped result: %s', raw_result)
|
||||
continue
|
||||
|
||||
if start <= count and count <= end: # pylint: disable=chained-comparison
|
||||
|
||||
@@ -54,7 +54,11 @@ def _obtain_token() -> str:
|
||||
token = CACHE.get("token")
|
||||
if token:
|
||||
return token
|
||||
resp = post(f"{base_url}/api/token/refresh", headers={"Origin": base_url}, cookies={"dp_api_token": "1"})
|
||||
resp = post(
|
||||
f"{base_url}/api/token/refresh",
|
||||
headers={"Origin": base_url, "Sec-Fetch-Mode": "cors"},
|
||||
cookies={"dp_api_token": "1"},
|
||||
)
|
||||
if not resp.ok:
|
||||
raise SearxEngineAPIException("failed to obtain dogpile token")
|
||||
token = resp.json()["token"]
|
||||
@@ -65,6 +69,7 @@ def _obtain_token() -> str:
|
||||
def request(query: str, params: "OnlineParams"):
|
||||
params["url"] = f"{base_url}/api/{dogpile_categ}"
|
||||
params["headers"]["Origin"] = base_url
|
||||
params["headers"]["Sec-Fetch-Mode"] = "cors"
|
||||
params["cookies"]["dp_api_token"] = "1"
|
||||
params["headers"]["x-dogpile-token"] = _obtain_token()
|
||||
|
||||
|
||||
@@ -510,12 +510,13 @@ def response(resp: "SXNG_Response") -> EngineResults:
|
||||
and "Your user agent:" not in zero_click
|
||||
and "URL Decoded:" not in zero_click
|
||||
):
|
||||
res.add(
|
||||
res.types.Answer(
|
||||
answer=zero_click,
|
||||
url=eval_xpath_getindex(doc, '//div[@id="zero_click_abstract"]/a/@href', 0),
|
||||
if zero_click_url := eval_xpath_getindex(doc, '//div[@id="zero_click_abstract"]/a/@href', 0, None):
|
||||
res.add(
|
||||
res.types.Answer(
|
||||
answer=zero_click,
|
||||
url=zero_click_url,
|
||||
)
|
||||
)
|
||||
)
|
||||
return res
|
||||
|
||||
|
||||
|
||||
@@ -74,7 +74,6 @@ def _fetch_first_page_link(
|
||||
headers=headers,
|
||||
impersonate="firefox",
|
||||
default_headers=False,
|
||||
timeout=2,
|
||||
)
|
||||
|
||||
if resp.status_code != 200:
|
||||
|
||||
@@ -88,6 +88,7 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
params["url"] = f"{base_url}/search/secure/?{urlencode(args)}"
|
||||
else:
|
||||
params["url"] = f"{base_url}/{privacywall_category}/?{urlencode(args)}"
|
||||
params["headers"]["Referer"] = f"{base_url}/"
|
||||
|
||||
|
||||
def _general_results(doc: "ElementBase") -> EngineResults:
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
.. _Resulthunter : https://resulthunter.com
|
||||
"""
|
||||
|
||||
import re
|
||||
import typing as t
|
||||
from urllib.parse import urlencode
|
||||
|
||||
from searx.enginelib import EngineCache
|
||||
from searx import locales
|
||||
from searx.exceptions import SearxEngineResponseException
|
||||
from searx.exceptions import SearxEngineAPIException, SearxEngineResponseException
|
||||
from searx.network import get
|
||||
from searx.result_types import EngineResults
|
||||
from searx.utils import eval_xpath_list, eval_xpath, extract_text
|
||||
|
||||
@@ -40,18 +43,46 @@ base_url = "https://resulthunter.com"
|
||||
resulthunter_categ = "web"
|
||||
"""Supported categories are ``web`` and ``images``."""
|
||||
|
||||
CACHE: EngineCache
|
||||
"""Cache for storing search token and cookies."""
|
||||
|
||||
|
||||
_SEARCH_TOKEN_RE = re.compile(r"window.__rhSearchToken\s*=\s*'(.*)'")
|
||||
|
||||
|
||||
def setup(_: dict[str, str]) -> bool | None:
|
||||
global CACHE # pylint: disable=global-statement
|
||||
CACHE = EngineCache("resulthunter")
|
||||
|
||||
def setup(_: dict[str, t.Any]) -> bool | None:
|
||||
if resulthunter_categ not in ("web", "images"):
|
||||
raise ValueError("invalid category: %s" % resulthunter_categ)
|
||||
|
||||
|
||||
def _get_search_token() -> tuple[str, dict[str, str]]:
|
||||
if cached := CACHE.get("token"):
|
||||
return cached
|
||||
|
||||
resp = get(base_url)
|
||||
token = _SEARCH_TOKEN_RE.search(resp.text)
|
||||
if not token:
|
||||
raise SearxEngineAPIException("failed to find search token")
|
||||
token = token.group(1)
|
||||
|
||||
cookies = dict(resp.cookies)
|
||||
CACHE.set("token", (token, cookies))
|
||||
return token, cookies
|
||||
|
||||
|
||||
def request(query: str, params: "OnlineParams") -> None:
|
||||
search_token, cookies = _get_search_token()
|
||||
params["cookies"] = cookies
|
||||
|
||||
args = {
|
||||
"q": query,
|
||||
"search_type": resulthunter_categ,
|
||||
"offset": params["pageno"] - 1,
|
||||
"search_source": "other",
|
||||
"search_source": "header",
|
||||
"st": search_token,
|
||||
}
|
||||
|
||||
# uses Brave's engine traits
|
||||
|
||||
@@ -48,16 +48,21 @@ def response(resp: "SXNG_Response") -> EngineResults:
|
||||
|
||||
mainline = [s for s in data["search"]["regions"] if s["name"] == "mainline"][0]
|
||||
for group in mainline["groups"]:
|
||||
for result in group["results"]:
|
||||
if not ("url" in result or "clickUrl" in result):
|
||||
continue
|
||||
match group["result_type"]:
|
||||
case "web":
|
||||
for result in group["results"]:
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=result.get("url") or result.get("clickUrl"),
|
||||
title=html_to_text(result["title"]),
|
||||
content=html_to_text(result["description"]),
|
||||
)
|
||||
)
|
||||
case "aylf":
|
||||
for result in group["results"]:
|
||||
res.add(res.types.LegacyResult(suggestion=result["term"]))
|
||||
|
||||
res.add(
|
||||
res.types.MainResult(
|
||||
url=result.get("url") or result.get("clickUrl"),
|
||||
title=html_to_text(result["title"]),
|
||||
content=html_to_text(result["description"]),
|
||||
)
|
||||
)
|
||||
case _:
|
||||
pass
|
||||
|
||||
return res
|
||||
|
||||
@@ -32,7 +32,7 @@ about = {
|
||||
}
|
||||
language = "de"
|
||||
|
||||
categories = ['general', 'news']
|
||||
categories = ['news']
|
||||
paging = True
|
||||
|
||||
results_per_page = 10
|
||||
|
||||
@@ -167,7 +167,7 @@ def get_results(
|
||||
infobox_id_lang: str | None = None
|
||||
infobox_urls: list[dict[str, str]] = []
|
||||
infobox_attributes: list[dict[str, str]] = []
|
||||
infobox_content = attribute_result.get("itemDescription", [])
|
||||
infobox_content: str = attribute_result.get("itemDescription", "")
|
||||
img_src: str | None = None
|
||||
img_src_priority = 0
|
||||
|
||||
|
||||
+18
-2
@@ -4,6 +4,8 @@
|
||||
import json
|
||||
import typing as t
|
||||
|
||||
from searx.exceptions import SearxEngineAPIException, SearxEngineTooManyRequestsException
|
||||
from searx.network import raise_for_httperror
|
||||
from searx.result_types import EngineResults
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
@@ -53,13 +55,27 @@ def request(query: str, params: "OnlineParams"):
|
||||
"source": "",
|
||||
}
|
||||
|
||||
params["raise_for_httperror"] = False
|
||||
|
||||
|
||||
def response(resp: "SXNG_Response") -> EngineResults:
|
||||
if resp.status_code in (400, 429):
|
||||
raise SearxEngineTooManyRequestsException()
|
||||
|
||||
raise_for_httperror(resp)
|
||||
|
||||
res = EngineResults()
|
||||
|
||||
# response is a Server-Side Events (SSE) stream
|
||||
data_raw = resp.text.split("\n", 1)[0].removeprefix("data: ")
|
||||
data = json.loads(data_raw)
|
||||
# we search for a JSON object with the "results" key
|
||||
data_parts = [line for line in resp.text.split("\n") if line]
|
||||
for data_raw in data_parts:
|
||||
data_raw = data_raw.removeprefix("data: ")
|
||||
data: dict[str, t.Any] = json.loads(data_raw)
|
||||
if "results" in data:
|
||||
break
|
||||
else:
|
||||
raise SearxEngineAPIException("no results in response")
|
||||
|
||||
result: dict[str, str]
|
||||
for result in data["results"]:
|
||||
|
||||
@@ -48,6 +48,7 @@ def request(query: str, params: "OnlineParams") -> None:
|
||||
{
|
||||
"Referer": f"{web_base_url}/",
|
||||
"Origin": web_base_url,
|
||||
"x-csrf-protection": "1",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@ def init():
|
||||
cfg_file = (settings_loader.get_user_cfg_folder() or pathlib.Path("/etc/searxng")) / "favicons.toml"
|
||||
if not cfg_file.exists():
|
||||
if is_active():
|
||||
logger.error(f"missing favicon config: {cfg_file}")
|
||||
logger.error("missing favicon config: %s", cfg_file)
|
||||
cfg_file = config.DEFAULT_CFG_TOML_PATH
|
||||
|
||||
logger.debug(f"load favicon config: {cfg_file}")
|
||||
logger.debug("load favicon config: %s", cfg_file)
|
||||
cfg = config.FaviconConfig.from_toml_file(cfg_file, use_cache=True)
|
||||
cache.init(cfg.cache)
|
||||
proxy.init(cfg.proxy)
|
||||
|
||||
@@ -352,7 +352,7 @@ CREATE TABLE IF NOT EXISTS blob_map (
|
||||
bytes_c = len(data or b"")
|
||||
if bytes_c > self.cfg.BLOB_MAX_BYTES:
|
||||
logger.info(
|
||||
"favicon of resolver: %s / authority: %s to big to cache (bytes: %s) " % (resolver, authority, bytes_c)
|
||||
"favicon of resolver: %s / authority: %s to big to cache (bytes: %s) ", resolver, authority, bytes_c
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ class Request(t.NamedTuple):
|
||||
|
||||
method: str
|
||||
url: str
|
||||
kwargs: dict[str, str] = {}
|
||||
kwargs: dict[str, str] = {} # pylint: disable=dangerous-default-value
|
||||
|
||||
@staticmethod
|
||||
def get(url: str, **kwargs: t.Any):
|
||||
|
||||
@@ -409,14 +409,6 @@ def initialize(
|
||||
if isinstance(network, str):
|
||||
NETWORKS[engine_name] = NETWORKS[network]
|
||||
|
||||
# the /image_proxy endpoint has a dedicated network.
|
||||
# same parameters than the default network, but HTTP/2 is disabled.
|
||||
# It decreases the CPU load average, and the total time is more or less the same
|
||||
if 'image_proxy' not in NETWORKS:
|
||||
image_proxy_params = default_params.copy()
|
||||
image_proxy_params['enable_http2'] = False
|
||||
NETWORKS['image_proxy'] = new_network(image_proxy_params, logger_name='image_proxy')
|
||||
|
||||
|
||||
@atexit.register
|
||||
def done():
|
||||
|
||||
@@ -19,9 +19,6 @@ if typing.TYPE_CHECKING:
|
||||
from searx.plugins import PluginCfg
|
||||
|
||||
|
||||
ahmia_blacklist: list = []
|
||||
|
||||
|
||||
def filter_url_field(result: "Result|LegacyResult", field_name: str, url_src: str) -> bool | str:
|
||||
"""Returns bool ``True`` to use URL unchanged (``False`` to ignore URL).
|
||||
If URL should be modified, the returned string is the new URL to use."""
|
||||
@@ -29,11 +26,15 @@ def filter_url_field(result: "Result|LegacyResult", field_name: str, url_src: st
|
||||
if field_name != "url":
|
||||
return True # use it unchanged
|
||||
|
||||
resolver_url = get_doi_resolver()
|
||||
if not resolver_url:
|
||||
return True # use it unchanged
|
||||
|
||||
doi = extract_doi(result.parsed_url)
|
||||
if doi and len(doi) < 50:
|
||||
for suffix in ("/", ".pdf", ".xml", "/full", "/meta", "/abstract"):
|
||||
doi = doi.removesuffix(suffix)
|
||||
new_url = get_doi_resolver() + doi
|
||||
new_url = resolver_url + doi
|
||||
if "doi" not in result:
|
||||
result["doi"] = doi
|
||||
log.debug("oa_doi_rewrite: [URL field: %s] %s -> %s", field_name, url_src, new_url)
|
||||
@@ -53,7 +54,7 @@ class SXNGPlugin(Plugin):
|
||||
id=self.id,
|
||||
name=gettext("Open Access DOI rewrite"),
|
||||
description=gettext("Avoid paywalls by redirecting to open-access versions of publications when available"),
|
||||
preference_section="general",
|
||||
preference_section=None,
|
||||
)
|
||||
|
||||
def on_result(
|
||||
@@ -83,7 +84,7 @@ def extract_doi(url):
|
||||
|
||||
def get_doi_resolver() -> str:
|
||||
doi_resolvers = get_setting("doi_resolvers")
|
||||
selected_resolver = sxng_request.preferences.get_value('doi_resolver')[0]
|
||||
if selected_resolver not in doi_resolvers:
|
||||
selected_resolver = get_setting("default_doi_resolver")
|
||||
selected_resolver = sxng_request.preferences.get_value("doi_resolver")
|
||||
if not selected_resolver or selected_resolver not in doi_resolvers:
|
||||
return ""
|
||||
return doi_resolvers[selected_resolver]
|
||||
|
||||
@@ -457,10 +457,10 @@ class Preferences:
|
||||
get_setting("ui.results_on_new_tab"),
|
||||
locked="results_on_new_tab" in self.cfg.lock,
|
||||
),
|
||||
'doi_resolver': MultipleChoiceSetting(
|
||||
[get_setting("default_doi_resolver")],
|
||||
"doi_resolver": EnumStringSetting(
|
||||
get_setting("default_doi_resolver"),
|
||||
locked="doi_resolver" in self.cfg.lock,
|
||||
choices=DOI_RESOLVERS,
|
||||
choices=["", *DOI_RESOLVERS],
|
||||
),
|
||||
'simple_style': EnumStringSetting(
|
||||
get_setting("ui.theme_args.simple_style"),
|
||||
@@ -536,6 +536,8 @@ class Preferences:
|
||||
self.plugins.parse_cookie(input_data.get('disabled_plugins', ''), input_data.get('enabled_plugins', ''))
|
||||
elif user_setting_name == 'tokens':
|
||||
self.tokens.parse(user_setting)
|
||||
if "oa_doi_rewrite" in self.plugins.choices:
|
||||
self.plugins.choices["oa_doi_rewrite"] = bool(self.get_value("doi_resolver"))
|
||||
|
||||
def parse_form(self, input_data: dict[str, str]):
|
||||
"""Parse formular (``<input>``) data from a ``flask.request.form``"""
|
||||
@@ -564,6 +566,8 @@ class Preferences:
|
||||
self.key_value_settings['categories'].parse_form(enabled_categories) # type: ignore
|
||||
self.engines.parse_form(disabled_engines)
|
||||
self.plugins.parse_form(disabled_plugins)
|
||||
if "oa_doi_rewrite" in self.plugins.choices:
|
||||
self.plugins.choices["oa_doi_rewrite"] = bool(self.get_value("doi_resolver"))
|
||||
|
||||
# cannot be used in case of engines or plugins
|
||||
def get_value(self, user_setting_name: str) -> t.Any:
|
||||
|
||||
@@ -182,6 +182,8 @@ class ResultContainer:
|
||||
|
||||
def close(self):
|
||||
self._closed = True
|
||||
# infobox with images first
|
||||
self.infoboxes.sort(key=lambda infobox: not infobox.img_src)
|
||||
|
||||
for result in self.main_results_map.values():
|
||||
result.score = calculate_score(result, result.priority)
|
||||
|
||||
@@ -126,9 +126,11 @@ class Search:
|
||||
actual_timeout = min(query_timeout, max_request_timeout)
|
||||
|
||||
logger.debug(
|
||||
"actual_timeout={0} (default_timeout={1}, ?timeout_limit={2}, max_request_timeout={3})".format(
|
||||
actual_timeout, default_timeout, query_timeout, max_request_timeout
|
||||
)
|
||||
"actual_timeout=%s (default_timeout=%s, ?timeout_limit=%s, max_request_timeout=%s)",
|
||||
actual_timeout,
|
||||
default_timeout,
|
||||
query_timeout,
|
||||
max_request_timeout,
|
||||
)
|
||||
|
||||
return requests, actual_timeout
|
||||
|
||||
@@ -71,7 +71,7 @@ class ProcessorMap(dict[str, EngineProcessor]):
|
||||
eng_type = getattr(eng_obj, "engine_type", "online")
|
||||
proc_cls = self.processor_types.get(eng_type)
|
||||
if proc_cls is None:
|
||||
logger.error("Engine '%s' is of unknown engine_type: %s", eng_type)
|
||||
logger.error("Engine of name '%s' is of unknown engine_type: %s", eng_name, eng_type)
|
||||
continue
|
||||
|
||||
# initialize (and register) the engine
|
||||
@@ -94,7 +94,7 @@ class ProcessorMap(dict[str, EngineProcessor]):
|
||||
# logger.debug("registered engine processor: %s", eng_proc.engine.name)
|
||||
else:
|
||||
logger.error(
|
||||
f"(PID {os.getpid()}) {eng_proc.engine.name}: can't register engines processor (init engine failed)"
|
||||
"(PID %s) %s: can't register engines processor (init engine failed)", os.getpid(), eng_proc.engine.name
|
||||
)
|
||||
|
||||
return eng_proc_ok
|
||||
|
||||
@@ -161,7 +161,7 @@ class EngineProcessor(ABC):
|
||||
try:
|
||||
init_ok = self.engine.init(eng_setting)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
logger.exception(f"(PID {os.getpid()}) {self.engine.name}: engine INIT failed, exception: {e}")
|
||||
logger.exception("(PID %s) %s: engine INIT failed, exception: %s", os.getpid(), self.engine.name, e)
|
||||
init_ok = False
|
||||
|
||||
# In older engines, None is returned from the init method, which is
|
||||
@@ -172,7 +172,7 @@ class EngineProcessor(ABC):
|
||||
init_ok = True
|
||||
|
||||
if not init_ok:
|
||||
logger.error(f"(PID {os.getpid()}) {self.engine.name}: engine init was not successful")
|
||||
logger.error("(PID %s) %s: engine init was not successful", os.getpid(), self.engine.name)
|
||||
|
||||
return init_ok
|
||||
|
||||
|
||||
+1
-1
@@ -470,7 +470,7 @@ engines:
|
||||
suggestion_xpath: .//a[starts-with(@href, "https://search.ayo.de")]
|
||||
disabled: true
|
||||
about:
|
||||
website: https://serach.ayo.de
|
||||
website: https://search.ayo.de
|
||||
use_official_api: false
|
||||
require_api_key: false
|
||||
results: HTML
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
import{n as e}from"../sxng-core.min.js";import{t}from"./DcK-mo-Y.min.js";var n=t(`search`),r=t(`q`),i=t(`clear_search`),a=window.matchMedia(`(max-width: 50em)`).matches,o=document.querySelector(`main`)?.id===`main_results`,s=Array.from(document.querySelectorAll(`#categories_container button.category`));a||o||r.focus(),a&&e(`focus`,r,()=>{requestAnimationFrame(()=>{let e=r.value.length;r.setSelectionRange(e,e),r.scrollLeft=r.scrollWidth})}),e(`click`,i,e=>{e.preventDefault(),r.value=``,r.focus()});for(let t of s)e(`click`,t,e=>{if(e.shiftKey){e.preventDefault(),t.classList.toggle(`selected`);return}for(let e of s)e.classList.toggle(`selected`,e===t)});if(document.querySelector(`div.search_filters`)){let t=document.getElementById(`safesearch`);t&&e(`change`,t,()=>n.submit());let r=document.getElementById(`time_range`);r&&e(`change`,r,()=>n.submit());let i=document.getElementById(`language`);i&&e(`change`,i,()=>n.submit())}e(`submit`,n,e=>{if(e.preventDefault(),s.length>0){let e=t(`selected-categories`);e.value=s.filter(e=>e.classList.contains(`selected`)).map(e=>e.name.replace(`category_`,``)).join(`,`)}n.submit()});
|
||||
//# sourceMappingURL=6liDwPCz.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"6liDwPCz.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\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(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\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,CAAC,CAAC,QAC3D,EAAyB,SAAS,cAAc,MAAM,CAAC,EAAE,KAAO,eAEhE,EAAuC,MAAM,KACjD,SAAS,iBAAoC,uCAAuC,CACtF,EAGM,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,EAAc,GAAsB,CAClD,EAAM,eAAe,EACrB,EAAY,MAAQ,GACpB,EAAY,MAAM,CACpB,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,CAAC,CACzD,IAAK,GAAW,EAAO,KAAK,QAAQ,YAAa,EAAE,CAAC,CAAC,CACrD,KAAK,GAAG,CACb,CAEA,EAAW,OAAO,CACpB,CAAC"}
|
||||
@@ -0,0 +1,2 @@
|
||||
import{n as e}from"../sxng-core.min.js";import{t}from"./DcK-mo-Y.min.js";var n=t(`search`),r=t(`q`),i=t(`clear_search`),a=window.matchMedia(`(max-width: 50em)`).matches,o=document.querySelector(`main`)?.id===`main_results`,s=Array.from(document.querySelectorAll(`#categories_container button.category`));a||o||r.focus(),a&&e(`focus`,r,()=>{requestAnimationFrame(()=>{let e=r.value.length;r.setSelectionRange(e,e),r.scrollLeft=r.scrollWidth})}),e(`click`,i,e=>{e.preventDefault(),r.value=``,r.focus()});for(let t of s)e(`click`,t,e=>{if(e.shiftKey)e.preventDefault(),t.classList.toggle(`selected`);else for(let e of s)e.classList.toggle(`selected`,e===t)});if(document.querySelector(`div.search_filters`)){let t=document.getElementById(`safesearch`);t&&e(`change`,t,()=>n.submit());let r=document.getElementById(`time_range`);r&&e(`change`,r,()=>n.submit());let i=document.getElementById(`language`);i&&e(`change`,i,()=>n.submit())}e(`submit`,n,e=>{if(e.preventDefault(),s.length>0){let e=t(`selected-categories`);e.value=s.filter(e=>e.classList.contains(`selected`)).map(e=>e.name.replace(`category_`,``)).join(`,`)}n.submit()});
|
||||
//# sourceMappingURL=BMrKiJ3q.min.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"BMrKiJ3q.min.js","names":["listen","searchForm","getElement","searchInput","searchReset","isMobile","isResultsPage","categoryButtons","end","event","button","categoryButton","safesearchElement","timeRangeElement","languageElement","searchCategories"],"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\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(\"click\", searchReset, (event: MouseEvent) => {\n event.preventDefault();\n searchInput.value = \"\";\n searchInput.focus();\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,IAAMC,EAA8BC,EAA4B,QAAQ,EAClEC,EAAgCD,EAA6B,GAAG,EAChEE,EAAiCF,EAA8B,cAAc,EAE7EG,EAAoB,OAAO,WAAW,mBAAmB,CAAC,CAAC,QAC3DC,EAAyB,SAAS,cAAc,MAAM,CAAC,EAAE,KAAO,eAEhEC,EAAuC,MAAM,KACjD,SAAS,iBAAoC,uCAAuC,CACtF,EAGMF,GAAYC,GAChBH,EAAY,MAAM,EAIhBE,GACFL,EAAO,QAASG,MAAmB,CAEjC,0BAA4B,CAC1B,IAAMK,EAAML,EAAY,MAAM,OAC9BA,EAAY,kBAAkBK,EAAKA,CAAG,EACtC,EAAY,WAAaL,EAAY,WACvC,CAAC,CACH,CAAC,EAGHH,EAAO,QAASI,EAAc,GAAsB,CAClDK,EAAM,eAAe,EACrB,EAAY,MAAQ,GACpBN,EAAY,MAAM,CACpB,CAAC,EAED,IAAK,IAAMO,KAAUH,EACnBP,EAAO,QAASU,EAAS,GAAsB,CAC7C,GAAID,EAAM,SACRA,EAAM,eAAe,EACrBC,EAAO,UAAU,OAAO,UAAU,OAKpC,IAAK,IAAMC,KAAkBJ,EAC3BI,EAAe,UAAU,OAAO,WAAYA,IAAmBD,CAAM,CAEzE,CAAC,EAGH,GAAI,SAAS,cAAc,oBAAoB,EAAG,CAChD,IAAME,EAAoB,SAAS,eAAe,YAAY,EAC1DA,GACFZ,EAAO,SAAUY,MAAyBX,EAAW,OAAO,CAAC,EAG/D,IAAMY,EAAmB,SAAS,eAAe,YAAY,EACzDA,GACFb,EAAO,SAAUa,MAAwBZ,EAAW,OAAO,CAAC,EAG9D,IAAMa,EAAkB,SAAS,eAAe,UAAU,EACtDA,GACFd,EAAO,SAAUc,MAAuBb,EAAW,OAAO,CAAC,CAE/D,CAGAD,EAAO,SAAUC,EAAa,GAAiB,CAG7C,GAFAQ,EAAM,eAAe,EAEjBF,EAAgB,OAAS,EAAG,CAC9B,IAAMQ,EAAmBb,EAA6B,qBAAqB,EAC3E,EAAiB,MAAQK,EACtB,OAAQ,GAAWG,EAAO,UAAU,SAAS,UAAU,CAAC,CAAC,CACzD,IAAK,GAAWA,EAAO,KAAK,QAAQ,YAAa,EAAE,CAAC,CAAC,CACrD,KAAK,GAAG,CACb,CAEAT,EAAW,OAAO,CACpB,CAAC"}
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"BuurKv-k.min.js","names":[],"sources":["../../../../../client/simple/src/js/Plugin.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Base class for client-side plugins.\n *\n * @remarks\n * Handle conditional loading of the plugin in:\n *\n * - client/simple/src/js/router.ts\n *\n * @abstract\n */\nexport abstract class Plugin {\n /**\n * Plugin name.\n */\n protected readonly id: string;\n\n /**\n * @remarks\n * Don't hold references of this instance outside the class.\n */\n protected constructor(id: string) {\n this.id = id;\n\n queueMicrotask(() => this.invoke());\n }\n\n private async invoke(): Promise<void> {\n try {\n console.debug(`[PLUGIN] ${this.id}: Running...`);\n const result = await this.run();\n if (!result) return;\n\n console.debug(`[PLUGIN] ${this.id}: Running post-exec...`);\n // @ts-expect-error\n void (await this.post(result as NonNullable<Awaited<ReturnType<this[\"run\"]>>>));\n } catch (error) {\n console.error(`[PLUGIN] ${this.id}:`, error);\n } finally {\n console.debug(`[PLUGIN] ${this.id}: Done.`);\n }\n }\n\n /**\n * Plugin goes here.\n *\n * @remarks\n * The plugin is already loaded at this point. If you wish to execute\n * conditions to exit early, consider moving the logic to:\n *\n * - client/simple/src/js/router.ts\n *\n * ...to avoid unnecessarily loading this plugin on the client.\n */\n protected abstract run(): Promise<unknown>;\n\n /**\n * Post-execution hook.\n *\n * @remarks\n * The hook is only executed if `#run()` returns a truthy value.\n */\n // @ts-expect-error\n protected abstract post(result: NonNullable<Awaited<ReturnType<this[\"run\"]>>>): Promise<void>;\n}\n"],"mappings":"AAYA,IAAsB,EAAtB,KAA6B,CAI3B,GAMA,YAAsB,EAAY,CAChC,KAAK,GAAK,EAEV,mBAAqB,KAAK,OAAO,CAAC,CACpC,CAEA,MAAc,QAAwB,CACpC,GAAI,CACF,QAAQ,MAAM,YAAY,KAAK,GAAG,aAAa,EAC/C,IAAM,EAAS,MAAM,KAAK,IAAI,EAC9B,GAAI,CAAC,EAAQ,OAEb,QAAQ,MAAM,YAAY,KAAK,GAAG,uBAAuB,EAEzD,MAAY,KAAK,KAAK,CAAuD,CAC/E,OAAS,EAAO,CACd,QAAQ,MAAM,YAAY,KAAK,GAAG,GAAI,CAAK,CAC7C,QAAU,CACR,QAAQ,MAAM,YAAY,KAAK,GAAG,QAAQ,CAC5C,CACF,CAuBF"}
|
||||
{"version":3,"file":"BuurKv-k.min.js","names":["Plugin","id","result","error"],"sources":["../../../../../client/simple/src/js/Plugin.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\n\n/**\n * Base class for client-side plugins.\n *\n * @remarks\n * Handle conditional loading of the plugin in:\n *\n * - client/simple/src/js/router.ts\n *\n * @abstract\n */\nexport abstract class Plugin {\n /**\n * Plugin name.\n */\n protected readonly id: string;\n\n /**\n * @remarks\n * Don't hold references of this instance outside the class.\n */\n protected constructor(id: string) {\n this.id = id;\n\n queueMicrotask(() => this.invoke());\n }\n\n private async invoke(): Promise<void> {\n try {\n console.debug(`[PLUGIN] ${this.id}: Running...`);\n const result = await this.run();\n if (!result) return;\n\n console.debug(`[PLUGIN] ${this.id}: Running post-exec...`);\n // @ts-expect-error\n void (await this.post(result as NonNullable<Awaited<ReturnType<this[\"run\"]>>>));\n } catch (error) {\n console.error(`[PLUGIN] ${this.id}:`, error);\n } finally {\n console.debug(`[PLUGIN] ${this.id}: Done.`);\n }\n }\n\n /**\n * Plugin goes here.\n *\n * @remarks\n * The plugin is already loaded at this point. If you wish to execute\n * conditions to exit early, consider moving the logic to:\n *\n * - client/simple/src/js/router.ts\n *\n * ...to avoid unnecessarily loading this plugin on the client.\n */\n protected abstract run(): Promise<unknown>;\n\n /**\n * Post-execution hook.\n *\n * @remarks\n * The hook is only executed if `#run()` returns a truthy value.\n */\n // @ts-expect-error\n protected abstract post(result: NonNullable<Awaited<ReturnType<this[\"run\"]>>>): Promise<void>;\n}\n"],"mappings":"AAYA,IAAsBA,EAAtB,KAA6B,CAI3B,GAMA,YAAsB,EAAY,CAChC,KAAK,GAAKC,EAEV,mBAAqB,KAAK,OAAO,CAAC,CACpC,CAEA,MAAc,QAAwB,CACpC,GAAI,CACF,QAAQ,MAAM,YAAY,KAAK,GAAG,aAAa,EAC/C,IAAMC,EAAS,MAAM,KAAK,IAAI,EAC9B,GAAI,CAACA,EAAQ,OAEb,QAAQ,MAAM,YAAY,KAAK,GAAG,uBAAuB,EAEzD,MAAY,KAAK,KAAKA,CAAuD,CAC/E,OAASC,EAAO,CACd,QAAQ,MAAM,YAAY,KAAK,GAAG,GAAIA,CAAK,CAC7C,QAAU,CACR,QAAQ,MAAM,YAAY,KAAK,GAAG,QAAQ,CAC5C,CACF,CAuBF"}
|
||||
@@ -0,0 +1,11 @@
|
||||
import{i as e,n as t,r as n}from"../sxng-core.min.js";import{t as r}from"./DK4yUVpy.min.js";
|
||||
/*!
|
||||
* swiped-events.js - v@version@
|
||||
* Pure JavaScript swipe events
|
||||
* https://github.com/john-doherty/swiped-events
|
||||
* @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
|
||||
* @author John Doherty <www.johndoherty.info>
|
||||
* @license MIT
|
||||
*/
|
||||
(function(e,t){typeof e.CustomEvent!=`function`&&(e.CustomEvent=function(e,n){n||={bubbles:!1,cancelable:!1,detail:void 0};var r=t.createEvent(`CustomEvent`);return r.initCustomEvent(e,n.bubbles,n.cancelable,n.detail),r},e.CustomEvent.prototype=e.Event.prototype),t.addEventListener(`touchstart`,u,!1),t.addEventListener(`touchmove`,d,!1),t.addEventListener(`touchend`,l,!1);var n=null,r=null,i=null,a=null,o=null,s=null,c=0;function l(e){if(s===e.target){var l=parseInt(f(s,`data-swipe-threshold`,`20`),10),u=f(s,`data-swipe-unit`,`px`),d=parseInt(f(s,`data-swipe-timeout`,`500`),10),p=Date.now()-o,m=``,h=e.changedTouches||e.touches||[];if(u===`vh`&&(l=Math.round(l/100*t.documentElement.clientHeight)),u===`vw`&&(l=Math.round(l/100*t.documentElement.clientWidth)),Math.abs(i)>Math.abs(a)?Math.abs(i)>l&&p<d&&(m=i>0?`swiped-left`:`swiped-right`):Math.abs(a)>l&&p<d&&(m=a>0?`swiped-up`:`swiped-down`),m!==``){var g={dir:m.replace(/swiped-/,``),touchType:(h[0]||{}).touchType||`direct`,fingers:c,xStart:parseInt(n,10),xEnd:parseInt((h[0]||{}).clientX||-1,10),yStart:parseInt(r,10),yEnd:parseInt((h[0]||{}).clientY||-1,10)};s.dispatchEvent(new CustomEvent(`swiped`,{bubbles:!0,cancelable:!0,detail:g})),s.dispatchEvent(new CustomEvent(m,{bubbles:!0,cancelable:!0,detail:g}))}n=null,r=null,o=null}}function u(e){e.target.getAttribute(`data-swipe-ignore`)!==`true`&&(s=e.target,o=Date.now(),n=e.touches[0].clientX,r=e.touches[0].clientY,i=0,a=0,c=e.touches.length)}function d(e){if(n&&r){var t=e.touches[0].clientX,o=e.touches[0].clientY;i=n-t,a=r-o}}function f(e,n,r){for(;e&&e!==t.documentElement;){var i=e.getAttribute(n);if(i)return i;e=e.parentNode}return r}})(window,document);var i,a=`${e.theme_static_path}/img/img_load_error.svg`,o=e=>{i&&clearTimeout(i);let t=e.querySelector(`.result-images-source img`);if(!t)return;let n=e.querySelector(`.image_thumbnail`);if(n){if(n.src===a)return;t.onerror=()=>{t.src=n.src},t.src=n.src}let r=t.getAttribute(`data-src`);r&&(i=setTimeout(()=>{t.src=r,t.removeAttribute(`data-src`)},1e3))},s=e=>{e.classList.contains(`thumbnail`)?e.closest(`a.thumbnail_link`)?.remove():e.classList.contains(`image_thumbnail`)&&e.src!==a&&(e.src=a)};document.addEventListener(`error`,e=>{let t=e.target;t instanceof HTMLImageElement&&s(t)},!0);for(let e of document.querySelectorAll(`img.thumbnail, #urls img.image_thumbnail`))e.complete&&e.naturalWidth===0&&s(e);document.querySelector(`#search_url button#copy_url`)?.style.setProperty(`display`,`block`),n.selectImage=e=>{document.getElementById(`results`)?.classList.add(`image-detail-open`),window.location.hash=`#image-viewer`,n.scrollPageToSelected?.(),e&&o(e)},n.closeDetail=()=>{document.getElementById(`results`)?.classList.remove(`image-detail-open`),window.location.hash===`#image-viewer`&&window.history.back(),n.scrollPageToSelected?.()},t(`click`,`.btn-collapse`,function(){let e=this.getAttribute(`data-btn-text-collapsed`),t=this.getAttribute(`data-btn-text-not-collapsed`),n=this.getAttribute(`data-target`);if(!(n&&e&&t))return;let i=document.querySelector(n);r(i);let a=this.classList.contains(`collapsed`),o=a?t:e,s=a?e:t;this.innerHTML=this.innerHTML.replace(s,o),this.classList.toggle(`collapsed`),i.classList.toggle(`invisible`)}),t(`click`,`.media-loader`,function(){let e=this.getAttribute(`data-target`);if(!e)return;let t=document.querySelector(`${e} > iframe`);if(r(t),!t.getAttribute(`src`)){let e=t.getAttribute(`data-src`);e&&t.setAttribute(`src`,e)}}),t(`click`,`#copy_url`,async function(){let e=this.parentElement?.querySelector(`pre`);if(r(e),window.isSecureContext)await navigator.clipboard.writeText(e.innerText);else{let t=window.getSelection();if(t){let n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n),document.execCommand(`copy`)}}this.dataset.copiedText&&(this.innerText=this.dataset.copiedText)}),t(`click`,`.result-detail-close`,e=>{e.preventDefault(),n.closeDetail?.()}),t(`click`,`.result-detail-previous`,e=>{e.preventDefault(),n.selectPrevious?.(!1)}),t(`click`,`.result-detail-next`,e=>{e.preventDefault(),n.selectNext?.(!1)}),window.addEventListener(`hashchange`,()=>{window.location.hash!==`#image-viewer`&&n.closeDetail?.()});var c=document.querySelectorAll(`.swipe-horizontal`);for(let e of c)t(`swiped-left`,e,()=>{n.selectNext?.(!1)}),t(`swiped-right`,e,()=>{n.selectPrevious?.(!1)});window.addEventListener(`scroll`,()=>{let e=document.getElementById(`backToTop`),t=document.getElementById(`results`);if(e&&t){let e=(document.documentElement.scrollTop||document.body.scrollTop)>=100;t.classList.toggle(`scrolling`,e)}},!0);
|
||||
//# sourceMappingURL=CFQtNTi4.min.js.map
|
||||
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
File diff suppressed because one or more lines are too long
+1
-1
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
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":"DK4yUVpy.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"}
|
||||
{"version":3,"file":"DK4yUVpy.min.js","names":["assertElement","element"],"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,IAAaA,EAAmC,GAA6C,CAC3F,GAAI,CAACC,EACH,MAAU,MAAM,uBAAuB,CAE3C"}
|
||||
@@ -1,11 +0,0 @@
|
||||
import{i as e,n as t,r as n}from"../sxng-core.min.js";import{t as r}from"./DK4yUVpy.min.js";
|
||||
/*!
|
||||
* swiped-events.js - v@version@
|
||||
* Pure JavaScript swipe events
|
||||
* https://github.com/john-doherty/swiped-events
|
||||
* @inspiration https://stackoverflow.com/questions/16348031/disable-scrolling-when-touch-moving-certain-element
|
||||
* @author John Doherty <www.johndoherty.info>
|
||||
* @license MIT
|
||||
*/
|
||||
(function(e,t){typeof e.CustomEvent!=`function`&&(e.CustomEvent=function(e,n){n||={bubbles:!1,cancelable:!1,detail:void 0};var r=t.createEvent(`CustomEvent`);return r.initCustomEvent(e,n.bubbles,n.cancelable,n.detail),r},e.CustomEvent.prototype=e.Event.prototype),t.addEventListener(`touchstart`,u,!1),t.addEventListener(`touchmove`,d,!1),t.addEventListener(`touchend`,l,!1);var n=null,r=null,i=null,a=null,o=null,s=null,c=0;function l(e){if(s===e.target){var l=parseInt(f(s,`data-swipe-threshold`,`20`),10),u=f(s,`data-swipe-unit`,`px`),d=parseInt(f(s,`data-swipe-timeout`,`500`),10),p=Date.now()-o,m=``,h=e.changedTouches||e.touches||[];if(u===`vh`&&(l=Math.round(l/100*t.documentElement.clientHeight)),u===`vw`&&(l=Math.round(l/100*t.documentElement.clientWidth)),Math.abs(i)>Math.abs(a)?Math.abs(i)>l&&p<d&&(m=i>0?`swiped-left`:`swiped-right`):Math.abs(a)>l&&p<d&&(m=a>0?`swiped-up`:`swiped-down`),m!==``){var g={dir:m.replace(/swiped-/,``),touchType:(h[0]||{}).touchType||`direct`,fingers:c,xStart:parseInt(n,10),xEnd:parseInt((h[0]||{}).clientX||-1,10),yStart:parseInt(r,10),yEnd:parseInt((h[0]||{}).clientY||-1,10)};s.dispatchEvent(new CustomEvent(`swiped`,{bubbles:!0,cancelable:!0,detail:g})),s.dispatchEvent(new CustomEvent(m,{bubbles:!0,cancelable:!0,detail:g}))}n=null,r=null,o=null}}function u(e){e.target.getAttribute(`data-swipe-ignore`)!==`true`&&(s=e.target,o=Date.now(),n=e.touches[0].clientX,r=e.touches[0].clientY,i=0,a=0,c=e.touches.length)}function d(e){if(n&&r){var t=e.touches[0].clientX,o=e.touches[0].clientY;i=n-t,a=r-o}}function f(e,n,r){for(;e&&e!==t.documentElement;){var i=e.getAttribute(n);if(i)return i;e=e.parentNode}return r}})(window,document);var i,a=`${e.theme_static_path}/img/img_load_error.svg`,o=e=>{i&&clearTimeout(i);let t=e.querySelector(`.result-images-source img`);if(!t)return;let n=e.querySelector(`.image_thumbnail`);if(n){if(n.src===a)return;t.onerror=()=>{t.src=n.src},t.src=n.src}let r=t.getAttribute(`data-src`);r&&(i=setTimeout(()=>{t.src=r,t.removeAttribute(`data-src`)},1e3))},s=e=>{if(e.classList.contains(`thumbnail`)){e.closest(`a.thumbnail_link`)?.remove();return}e.classList.contains(`image_thumbnail`)&&e.src!==a&&(e.src=a)};document.addEventListener(`error`,e=>{let t=e.target;t instanceof HTMLImageElement&&s(t)},!0);for(let e of document.querySelectorAll(`img.thumbnail, #urls img.image_thumbnail`))e.complete&&e.naturalWidth===0&&s(e);document.querySelector(`#search_url button#copy_url`)?.style.setProperty(`display`,`block`),n.selectImage=e=>{document.getElementById(`results`)?.classList.add(`image-detail-open`),window.location.hash=`#image-viewer`,n.scrollPageToSelected?.(),e&&o(e)},n.closeDetail=()=>{document.getElementById(`results`)?.classList.remove(`image-detail-open`),window.location.hash===`#image-viewer`&&window.history.back(),n.scrollPageToSelected?.()},t(`click`,`.btn-collapse`,function(){let e=this.getAttribute(`data-btn-text-collapsed`),t=this.getAttribute(`data-btn-text-not-collapsed`),n=this.getAttribute(`data-target`);if(!(n&&e&&t))return;let i=document.querySelector(n);r(i);let a=this.classList.contains(`collapsed`),o=a?t:e,s=a?e:t;this.innerHTML=this.innerHTML.replace(s,o),this.classList.toggle(`collapsed`),i.classList.toggle(`invisible`)}),t(`click`,`.media-loader`,function(){let e=this.getAttribute(`data-target`);if(!e)return;let t=document.querySelector(`${e} > iframe`);if(r(t),!t.getAttribute(`src`)){let e=t.getAttribute(`data-src`);e&&t.setAttribute(`src`,e)}}),t(`click`,`#copy_url`,async function(){let e=this.parentElement?.querySelector(`pre`);if(r(e),window.isSecureContext)await navigator.clipboard.writeText(e.innerText);else{let t=window.getSelection();if(t){let n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n),document.execCommand(`copy`)}}this.dataset.copiedText&&(this.innerText=this.dataset.copiedText)}),t(`click`,`.result-detail-close`,e=>{e.preventDefault(),n.closeDetail?.()}),t(`click`,`.result-detail-previous`,e=>{e.preventDefault(),n.selectPrevious?.(!1)}),t(`click`,`.result-detail-next`,e=>{e.preventDefault(),n.selectNext?.(!1)}),window.addEventListener(`hashchange`,()=>{window.location.hash!==`#image-viewer`&&n.closeDetail?.()});var c=document.querySelectorAll(`.swipe-horizontal`);for(let e of c)t(`swiped-left`,e,()=>{n.selectNext?.(!1)}),t(`swiped-right`,e,()=>{n.selectPrevious?.(!1)});window.addEventListener(`scroll`,()=>{let e=document.getElementById(`backToTop`),t=document.getElementById(`results`);if(e&&t){let e=(document.documentElement.scrollTop||document.body.scrollTop)>=100;t.classList.toggle(`scrolling`,e)}},!0);
|
||||
//# sourceMappingURL=DT2OB9zd.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"DcK-mo-Y.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"}
|
||||
{"version":3,"file":"DcK-mo-Y.min.js","names":["assertElement","getElement","element","id","options"],"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,SAAgBC,EAAc,EAAY,EAAmB,CAAC,EAAa,CACzE,EAAQ,SAAW,GAEnB,IAAMC,EAAU,SAAS,eAAeC,CAAE,EAM1C,OAJIC,EAAQ,QACVJ,EAAcE,CAAO,EAGhBA,CACT"}
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
{"version":3,"file":"e2-9fzwE.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,EAAA,CACzB,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"}
|
||||
{"version":3,"file":"e2-9fzwE.min.js","names":["settings","listen","http","assertElement","engineDescriptions","loadEngineDescriptions","error","engine_name","description","source","elements","sourceText","element","toggleEngines","engineToggle","engineToggles","enable","engineElements","engineElement","enableAllEngines","engine","disableAllEngines","target","selection","range"],"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,IAAII,EAEEC,EAAyB,SAA2B,CACxD,GAAI,GACJ,IAAI,CAEF,EAAqB,MAAM,MADTH,EAAK,MAAO,0BAA0B,EAAA,CACzB,KAAK,CACtC,OAASI,EAAO,CACd,QAAQ,MAAM,qCAAsCA,CAAK,CAC3D,CACA,GAAKF,EAEL,IAAK,GAAM,CAACG,EAAa,CAACC,EAAaC,MAAY,OAAO,QAAQL,CAAkB,EAAG,CACrF,IAAMM,EAAW,SAAS,iBAA8B,sBAAsBH,EAAY,uBAAuB,EAC3GI,EAAa,QAAQX,EAAS,cAAc,OAAO,SAASS,EAAO,OAEzE,IAAK,IAAMG,KAAWF,EACpB,EAAQ,UAAYF,EAAcG,CAEtC,CAVA,CAWF,EAEME,GAAiB,EAAiB,IAAsD,CAC5F,IAAK,IAAMC,KAAgBC,EAErBD,EAAa,eACf,EAAa,QAAU,CAACE,EAG9B,EAEMC,EAA0C,SAAS,iBAA8B,oBAAoB,EAC3G,IAAK,IAAMC,KAAiBD,EAC1BhB,EAAO,aAAciB,EAAeb,CAAsB,EAG5D,IAAMU,EAA8C,SAAS,iBAC3D,mDACF,EAEMI,EAA4C,SAAS,iBAA8B,qBAAqB,EAC9G,IAAK,IAAMC,KAAUD,EACnBlB,EAAO,QAASmB,MAAcP,EAAc,GAAME,CAAa,CAAC,EAGlE,IAAMM,EAA6C,SAAS,iBAA8B,sBAAsB,EAChH,IAAK,IAAMD,KAAUC,EACnBpB,EAAO,QAASmB,MAAcP,EAAc,GAAOE,CAAa,CAAC,EAGnEd,EAAO,QAAS,aAAc,gBAAmC,CAC/D,IAAMqB,EAAS,KAAK,eAAe,cAA8B,KAAK,EAGtE,GAFAnB,EAAcmB,CAAM,EAEhB,OAAO,gBACT,MAAM,UAAU,UAAU,UAAUA,EAAO,SAAS,MAC/C,CACL,IAAMC,EAAY,OAAO,aAAa,EACtC,GAAIA,EAAW,CACb,IAAMC,EAAQ,SAAS,YAAY,EACnCA,EAAM,mBAAmBF,CAAM,EAC/BC,EAAU,gBAAgB,EAC1BA,EAAU,SAASC,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
@@ -41,7 +41,7 @@
|
||||
]
|
||||
},
|
||||
"src/js/main/keyboard.ts": {
|
||||
"file": "chunk/CX4Qzp80.min.js",
|
||||
"file": "chunk/CGcztD0S.min.js",
|
||||
"name": "keyboard",
|
||||
"src": "src/js/main/keyboard.ts",
|
||||
"isDynamicEntry": true,
|
||||
@@ -61,7 +61,7 @@
|
||||
]
|
||||
},
|
||||
"src/js/main/results.ts": {
|
||||
"file": "chunk/DT2OB9zd.min.js",
|
||||
"file": "chunk/CFQtNTi4.min.js",
|
||||
"name": "results",
|
||||
"src": "src/js/main/results.ts",
|
||||
"isDynamicEntry": true,
|
||||
@@ -71,7 +71,7 @@
|
||||
]
|
||||
},
|
||||
"src/js/main/search.ts": {
|
||||
"file": "chunk/6liDwPCz.min.js",
|
||||
"file": "chunk/BMrKiJ3q.min.js",
|
||||
"name": "search",
|
||||
"src": "src/js/main/search.ts",
|
||||
"isDynamicEntry": true,
|
||||
@@ -81,7 +81,7 @@
|
||||
]
|
||||
},
|
||||
"src/js/plugin/Calculator.ts": {
|
||||
"file": "chunk/Di4V4jt_.min.js",
|
||||
"file": "chunk/CGtCrbI8.min.js",
|
||||
"name": "calculator",
|
||||
"src": "src/js/plugin/Calculator.ts",
|
||||
"isDynamicEntry": true,
|
||||
@@ -103,7 +103,7 @@
|
||||
]
|
||||
},
|
||||
"src/js/plugin/MapView.ts": {
|
||||
"file": "chunk/zYDfzRRQ.min.js",
|
||||
"file": "chunk/DAKwL16e.min.js",
|
||||
"name": "mapview",
|
||||
"src": "src/js/plugin/MapView.ts",
|
||||
"isDynamicEntry": true,
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./chunk/zYDfzRRQ.min.js","./chunk/BuurKv-k.min.js","./sxng-mapview.min.css","./chunk/D3mcqWOe.min.js","./chunk/DK4yUVpy.min.js","./chunk/DcK-mo-Y.min.js","./chunk/Di4V4jt_.min.js","./chunk/CX4Qzp80.min.js","./chunk/6liDwPCz.min.js","./chunk/Bs-FMxfE.min.js","./chunk/DT2OB9zd.min.js","./chunk/e2-9fzwE.min.js"])))=>i.map(i=>d[i]);
|
||||
var e={index:`index`,results:`results`,preferences:`preferences`,unknown:`unknown`},t={closeDetail:void 0,scrollPageToSelected:void 0,selectImage:void 0,selectNext:void 0,selectPrevious:void 0},n=()=>{let t=document.querySelector(`meta[name="endpoint"]`)?.getAttribute(`content`);return t&&t in e?t:e.unknown},r=()=>{let e=document.querySelector(`script[client_settings]`)?.getAttribute(`client_settings`);if(!e)return{};try{return JSON.parse(atob(e))}catch(e){return console.error(`Failed to load client_settings:`,e),{}}},i=async(e,t,n)=>{let r=new AbortController,i=setTimeout(()=>r.abort(),n?.timeout??3e4),a=await fetch(t,{body:n?.body,method:e,signal:r.signal}).finally(()=>clearTimeout(i));if(!a.ok)throw Error(a.statusText);return a},a=(e,t,n,r)=>{if(typeof t!=`string`){t.addEventListener(e,n,r);return}document.addEventListener(e,e=>{for(let r of e.composedPath())if(r instanceof HTMLElement&&r.matches(t)){try{n.call(r,e)}catch(e){console.error(e)}break}},r)},o=(e,t)=>{for(let e of t?.on??[])if(!e)return;document.readyState===`loading`?a(`DOMContentLoaded`,document,e,{once:!0}):e()},s=n(),c=r(),l=(e,t)=>{u(t)&&e()},u=e=>{switch(e.on){case`global`:return!0;case`endpoint`:return!!e.where.includes(s)}},d=`modulepreload`,f=function(e,t){return new URL(e,t).href},p={},m=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,import.meta.url).href}r=o(t.map(t=>{if(t=f(t,n),t=s(t),t in p)return;p[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:d,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(/* @__PURE__ */ Error(`Unable to preload CSS for ${t}`)))})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};o(()=>{document.documentElement.classList.remove(`no-js`),document.documentElement.classList.add(`js`),a(`click`,`.close`,function(){this.parentNode?.classList.add(`invisible`)}),a(`click`,`.searxng_init_map`,async function(t){t.preventDefault(),this.classList.remove(`searxng_init_map`),l(()=>m(async()=>{let{default:e}=await import(`./chunk/zYDfzRRQ.min.js`);return{default:e}},__vite__mapDeps([0,1,2]),import.meta.url).then(({default:e})=>new e(this)),{on:`endpoint`,where:[e.results]})}),c.plugins?.includes(`infiniteScroll`)&&l(()=>m(async()=>{let{default:e}=await import(`./chunk/D3mcqWOe.min.js`);return{default:e}},__vite__mapDeps([3,1,4,5]),import.meta.url).then(({default:e})=>new e),{on:`endpoint`,where:[e.results]}),c.plugins?.includes(`calculator`)&&l(()=>m(async()=>{let{default:e}=await import(`./chunk/Di4V4jt_.min.js`);return{default:e}},__vite__mapDeps([6,1,5,4]),import.meta.url).then(({default:e})=>new e),{on:`endpoint`,where:[e.results]})}),o(()=>{m(()=>import(`./chunk/CX4Qzp80.min.js`),__vite__mapDeps([7,4]),import.meta.url),m(()=>import(`./chunk/6liDwPCz.min.js`),__vite__mapDeps([8,5,4]),import.meta.url),c.autocomplete&&m(()=>import(`./chunk/Bs-FMxfE.min.js`),__vite__mapDeps([9,4]),import.meta.url)},{on:[s===e.index]}),o(()=>{m(()=>import(`./chunk/CX4Qzp80.min.js`),__vite__mapDeps([7,4]),import.meta.url),m(()=>import(`./chunk/DT2OB9zd.min.js`),__vite__mapDeps([10,4]),import.meta.url),m(()=>import(`./chunk/6liDwPCz.min.js`),__vite__mapDeps([8,5,4]),import.meta.url),c.autocomplete&&m(()=>import(`./chunk/Bs-FMxfE.min.js`),__vite__mapDeps([9,4]),import.meta.url)},{on:[s===e.results]}),o(()=>{m(()=>import(`./chunk/e2-9fzwE.min.js`),__vite__mapDeps([11,4]),import.meta.url)},{on:[s===e.preferences]});export{c as i,a as n,t as r,i as t};
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./chunk/DAKwL16e.min.js","./chunk/BuurKv-k.min.js","./sxng-mapview.min.css","./chunk/D3mcqWOe.min.js","./chunk/DK4yUVpy.min.js","./chunk/DcK-mo-Y.min.js","./chunk/CGtCrbI8.min.js","./chunk/CGcztD0S.min.js","./chunk/BMrKiJ3q.min.js","./chunk/Bs-FMxfE.min.js","./chunk/CFQtNTi4.min.js","./chunk/e2-9fzwE.min.js"])))=>i.map(i=>d[i]);
|
||||
var e={index:`index`,results:`results`,preferences:`preferences`,unknown:`unknown`},t={closeDetail:void 0,scrollPageToSelected:void 0,selectImage:void 0,selectNext:void 0,selectPrevious:void 0},n=()=>{let t=document.querySelector(`meta[name="endpoint"]`)?.getAttribute(`content`);return t&&t in e?t:e.unknown},r=()=>{let e=document.querySelector(`script[client_settings]`)?.getAttribute(`client_settings`);if(!e)return{};try{return JSON.parse(atob(e))}catch(e){return console.error(`Failed to load client_settings:`,e),{}}},i=async(e,t,n)=>{let r=new AbortController,i=setTimeout(()=>r.abort(),n?.timeout??3e4),a=await fetch(t,{body:n?.body,method:e,signal:r.signal}).finally(()=>clearTimeout(i));if(!a.ok)throw Error(a.statusText);return a},a=(e,t,n,r)=>{typeof t==`string`?document.addEventListener(e,e=>{for(let r of e.composedPath())if(r instanceof HTMLElement&&r.matches(t)){try{n.call(r,e)}catch(e){console.error(e)}break}},r):t.addEventListener(e,n,r)},o=(e,t)=>{for(let e of t?.on??[])if(!e)return;document.readyState===`loading`?a(`DOMContentLoaded`,document,e,{once:!0}):e()},s=n(),c=r(),l=(e,t)=>{u(t)&&e()},u=e=>{switch(e.on){case`global`:return!0;case`endpoint`:return!!e.where.includes(s)}},d=`modulepreload`,f=function(e,t){return new URL(e,t).href},p={},m=function(e){return e.pathname.endsWith(`.css`)},h=function(e,t,n){if(t in e)return e[t];let r=n();if(!r){e[t]=void 0;return}let i=r.then(()=>{e[t]=void 0},n=>{throw e[t]=void 0,n});return e[t]=i,i},g=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=o(t.map(t=>{t=f(t,n);let r=s(t),i=m(r);return h(p,r.href,()=>{if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let t=document.createElement(`link`);if(t.rel=i?`stylesheet`:d,i||(t.as=`script`),t.crossOrigin=``,t.href=r.href,a&&t.setAttribute(`nonce`,a),document.head.appendChild(t),i)return new Promise((e,n)=>{t.addEventListener(`load`,e),t.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${r}`)))})})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};o(()=>{document.documentElement.classList.remove(`no-js`),document.documentElement.classList.add(`js`),a(`click`,`.close`,function(){this.parentNode?.classList.add(`invisible`)}),a(`click`,`.searxng_init_map`,async function(t){t.preventDefault(),this.classList.remove(`searxng_init_map`),l(()=>g(async()=>{let{default:e}=await import(`./chunk/DAKwL16e.min.js`);return{default:e}},__vite__mapDeps([0,1,2]),import.meta.url).then(({default:e})=>new e(this)),{on:`endpoint`,where:[e.results]})}),c.plugins?.includes(`infiniteScroll`)&&l(()=>g(async()=>{let{default:e}=await import(`./chunk/D3mcqWOe.min.js`);return{default:e}},__vite__mapDeps([3,1,4,5]),import.meta.url).then(({default:e})=>new e),{on:`endpoint`,where:[e.results]}),c.plugins?.includes(`calculator`)&&l(()=>g(async()=>{let{default:e}=await import(`./chunk/CGtCrbI8.min.js`);return{default:e}},__vite__mapDeps([6,1,5,4]),import.meta.url).then(({default:e})=>new e),{on:`endpoint`,where:[e.results]})}),o(()=>{g(()=>import(`./chunk/CGcztD0S.min.js`),__vite__mapDeps([7,4]),import.meta.url),g(()=>import(`./chunk/BMrKiJ3q.min.js`),__vite__mapDeps([8,5,4]),import.meta.url),c.autocomplete&&g(()=>import(`./chunk/Bs-FMxfE.min.js`),__vite__mapDeps([9,4]),import.meta.url)},{on:[s===e.index]}),o(()=>{g(()=>import(`./chunk/CGcztD0S.min.js`),__vite__mapDeps([7,4]),import.meta.url),g(()=>import(`./chunk/CFQtNTi4.min.js`),__vite__mapDeps([10,4]),import.meta.url),g(()=>import(`./chunk/BMrKiJ3q.min.js`),__vite__mapDeps([8,5,4]),import.meta.url),c.autocomplete&&g(()=>import(`./chunk/Bs-FMxfE.min.js`),__vite__mapDeps([9,4]),import.meta.url)},{on:[s===e.results]}),o(()=>{g(()=>import(`./chunk/e2-9fzwE.min.js`),__vite__mapDeps([11,4]),import.meta.url)},{on:[s===e.preferences]});export{c as i,a as n,t as r,i as t};
|
||||
//# sourceMappingURL=sxng-core.min.js.map
|
||||
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
@@ -183,16 +183,16 @@
|
||||
{%- if 'favicon_resolver' not in locked_preferences -%}
|
||||
{%- include 'simple/preferences/favicon.html' -%}
|
||||
{%- endif -%}
|
||||
{%- if 'doi_resolver' not in locked_preferences -%}
|
||||
{%- include 'simple/preferences/doi_resolver.html' -%}
|
||||
{%- endif -%}
|
||||
{% if 'safesearch' not in locked_preferences %}
|
||||
{%- include 'simple/preferences/safesearch.html' -%}
|
||||
{%- endif -%}
|
||||
{%- include 'simple/preferences/tokens.html' -%}
|
||||
{{- plugin_preferences('general') -}}
|
||||
|
||||
|
||||
{%- if 'doi_resolver' not in locked_preferences %}
|
||||
{%- include 'simple/preferences/doi_resolver.html' -%}
|
||||
{%- if engines_with_tokens -%}
|
||||
{%- include 'simple/preferences/tokens.html' -%}
|
||||
{%- endif -%}
|
||||
{{- plugin_preferences('general') -}}
|
||||
{{- tab_footer() -}}
|
||||
|
||||
{# tab: ui #}
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
<div class="pref-group">{{- _('Digital Object Identifier (DOI)') -}}</div>
|
||||
|
||||
{{- plugin_preferences('general/doi_resolver') -}}
|
||||
|
||||
<fieldset>{{- '' -}}
|
||||
<legend id="pref_doi_resolver">{{- _('Open Access DOI resolver') -}}</legend>{{- '' -}}
|
||||
<legend id="pref_doi_resolver">{{- _('DOI Resolver') -}}</legend>{{- '' -}}
|
||||
<div class="value">{{- '' -}}
|
||||
<select id='doi_resolver' name='doi_resolver' aria-labelledby="pref_doi_resolver">{{- '' -}}
|
||||
{%- for doi_resolver_name,doi_resolver_url in doi_resolvers.items() -%}
|
||||
<select name="doi_resolver" aria-labelledby="pref_doi_resolver">{{- '' -}}
|
||||
<option value=""> - </option>
|
||||
{%- for doi_resolver_name in doi_resolvers -%}
|
||||
<option value="{{ doi_resolver_name }}"
|
||||
{%- if doi_resolver_url == current_doi_resolver %} selected="selected" {%- endif -%}>
|
||||
{{- doi_resolver_name }} - {{ doi_resolver_url -}}
|
||||
{%- if doi_resolver_name == current_doi_resolver %} selected="selected" {%- endif -%}>
|
||||
{{- doi_resolver_name -}}
|
||||
</option>
|
||||
{%- endfor -%}
|
||||
</select>{{- '' -}}
|
||||
</div>{{- '' -}}
|
||||
<div class="description">
|
||||
{{- _('Select service used by DOI rewrite') -}}
|
||||
{{- _('Avoid paywalls by redirecting to open-access versions of publications when available') -}}
|
||||
</div>{{- '' -}}
|
||||
</fieldset>{{- '' -}}
|
||||
|
||||
Binary file not shown.
@@ -23,9 +23,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"PO-Revision-Date: 2026-06-19 05:08+0000\n"
|
||||
"Last-Translator: Raithlin <raithlin@noreply.codeberg.org>\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-10-09 14:20+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: af\n"
|
||||
"Language-Team: Afrikaans "
|
||||
"<https://translate.codeberg.org/projects/searxng/searxng/af/>\n"
|
||||
@@ -53,7 +53,7 @@ msgstr "toeps"
|
||||
#. CATEGORY_NAMES['BLOGS']
|
||||
#: searx/searxng.msg
|
||||
msgid "blogs"
|
||||
msgstr ""
|
||||
msgstr "webjoernaal"
|
||||
|
||||
#. CATEGORY_NAMES['DICTIONARIES']
|
||||
#: searx/searxng.msg
|
||||
@@ -73,7 +73,7 @@ msgstr "algemeen"
|
||||
#. CATEGORY_NAMES['ICONS']
|
||||
#: searx/searxng.msg
|
||||
msgid "icons"
|
||||
msgstr ""
|
||||
msgstr "ikone"
|
||||
|
||||
#. CATEGORY_NAMES['IMAGES']
|
||||
#: searx/searxng.msg
|
||||
@@ -98,7 +98,7 @@ msgstr "kaart"
|
||||
#. CATEGORY_NAMES['MOVIES']
|
||||
#: searx/searxng.msg
|
||||
msgid "movies"
|
||||
msgstr ""
|
||||
msgstr "flieks"
|
||||
|
||||
#. CATEGORY_NAMES['MUSIC']
|
||||
#: searx/searxng.msg
|
||||
@@ -158,12 +158,12 @@ msgstr "sagteware wiki's"
|
||||
#. CATEGORY_NAMES['STOCK_IMAGES']
|
||||
#: searx/searxng.msg
|
||||
msgid "stock images"
|
||||
msgstr ""
|
||||
msgstr "voorraadbeelde"
|
||||
|
||||
#. CATEGORY_NAMES['TRANSLATE']
|
||||
#: searx/searxng.msg
|
||||
msgid "translate"
|
||||
msgstr ""
|
||||
msgstr "vertaal"
|
||||
|
||||
#. CATEGORY_NAMES['TV']
|
||||
#: searx/searxng.msg
|
||||
@@ -178,7 +178,7 @@ msgstr "videos"
|
||||
#. CATEGORY_NAMES['WEATHER']
|
||||
#: searx/searxng.msg
|
||||
msgid "weather"
|
||||
msgstr ""
|
||||
msgstr "weer"
|
||||
|
||||
#. CATEGORY_NAMES['WEB']
|
||||
#: searx/searxng.msg
|
||||
@@ -589,15 +589,107 @@ msgstr "Bron"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "Fout met die laai van die volgende bladsy"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "Ongeldige opstellings, redigeer asb jou voorkeure"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "Ongeldige opstellings"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "soekfout"
|
||||
|
||||
@@ -808,11 +900,12 @@ msgstr ""
|
||||
"Laai die volgende bladsy outomaties wanneer na die onderkant van die "
|
||||
"huidige bladsy geblaai word"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "oop toegang DOI oorskryf"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1433,17 +1526,9 @@ msgstr "Voeg gekopieerde voorkeur-hash (sonder URL) in om te herstel"
|
||||
msgid "Preferences hash"
|
||||
msgstr "Voorkeure hash"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "Digitale Objekidentifiseerder (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Ooptoegang DOI-oplosser"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "Kies diens wat deur DOI herskryf gebruik word"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2196,3 +2281,12 @@ msgstr "versteek video"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Enjin"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "Digitale Objekidentifiseerder (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Ooptoegang DOI-oplosser"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "Kies diens wat deur DOI herskryf gebruik word"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -33,7 +33,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-06-28 18:07+0000\n"
|
||||
"Last-Translator: nebras <nebras@noreply.codeberg.org>\n"
|
||||
"Language: ar\n"
|
||||
@@ -600,15 +600,107 @@ msgstr "مصدر"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "خطأ في تحميل الصفحة التالية"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "إعدادات غير صالحة، يرجى تعديل تفضيلاتك"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "إعدادات غير صالحة"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "خطأ في البحث"
|
||||
|
||||
@@ -815,11 +907,12 @@ msgid ""
|
||||
" page"
|
||||
msgstr "يحمل الصفحة التالية تلقائيًا عند التمرير إلى أسفل الصفحة الحالية"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "فتح الوصول معرف الكائن الرقمي إعادة كتابة"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1441,17 +1534,9 @@ msgstr "أدخل تجزئة التفضيلات المنسوخة (بدون عنو
|
||||
msgid "Preferences hash"
|
||||
msgstr "تجزئة التفضيلات"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "معرف الكائن الرقمي (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "فتح الوصول إلى محلل DOI"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "حدد الخدمة التي يستخدمه المعرف الرقمي. (DOI)"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2434,3 +2519,12 @@ msgstr "إخفاء الفيديو"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "محرك"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "معرف الكائن الرقمي (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "فتح الوصول إلى محلل DOI"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "حدد الخدمة التي يستخدمه المعرف الرقمي. (DOI)"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -23,7 +23,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-08-21 20:54+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: bg\n"
|
||||
@@ -589,15 +589,107 @@ msgstr "Източник"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "Грешка при зареждането на следващата страница"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "Неправилни настройки, моля редактирайте предпочитанията си"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "Невалидни настройки"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "Грешка при търсенето"
|
||||
|
||||
@@ -804,11 +896,12 @@ msgid ""
|
||||
" page"
|
||||
msgstr "Автоматично зареждане на следващата страница"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "Отворен достъп DOI пренаписване"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1429,19 +1522,9 @@ msgstr "Вмъкнете копирания хеш на предпочитани
|
||||
msgid "Preferences hash"
|
||||
msgstr "Хеш на предпочитанията"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "Идентификатор на цифров обект (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Дигитален идентификатор на обекти с отворен достъп"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
"Изберете услуга използвана от \"Идентификатор на дигитален обект“ (DOI) "
|
||||
"пренаписване"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
#, fuzzy
|
||||
@@ -2434,3 +2517,14 @@ msgstr "скрий видеото"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Търсачка"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "Идентификатор на цифров обект (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Дигитален идентификатор на обекти с отворен достъп"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr ""
|
||||
#~ "Изберете услуга използвана от \"Идентификатор"
|
||||
#~ " на дигитален обект“ (DOI) пренаписване"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -29,7 +29,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: bn\n"
|
||||
@@ -595,15 +595,107 @@ msgstr "উৎস"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "পরবর্তী পৃষ্ঠাটি লোড করায় ত্রুটি দেখা যাচ্ছে"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "অকেজো সেটিংস, অনুগ্রহ করে আপনার পছন্দগুলি সম্পাদনা করুন"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "অকেজো সেটিংস"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "সার্চ ত্রুটি"
|
||||
|
||||
@@ -810,11 +902,12 @@ msgstr ""
|
||||
"বর্তমান পৃষ্ঠার নীচে স্ক্রোল করার সময় স্বয়ংক্রিয়ভাবে পরবর্তী পৃষ্ঠা "
|
||||
"লোড করুন"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "পুনর্লিখিত DOI উন্মুক্ত প্রবেশ"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1429,17 +1522,9 @@ msgstr "অনুলিপিকৃত হ্যাশ এখানে দাও
|
||||
msgid "Preferences hash"
|
||||
msgstr "পছন্দসমূহের হ্যাশ"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "ডিজিটাল অবজেক্ট আইডেন্টিফায়ার (ডই)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "উন্মুক্ত প্রবেশাধিকারযুক্ত DOI সমাধানদাতা"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "পুনর্লিখিত DOI দ্বারা ব্যবহৃত সার্ভিস নির্বাচিত করুণ"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2192,3 +2277,12 @@ msgstr "ভিডিও লুকিয়ে ফেলুন"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "ইঞ্জিন"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "ডিজিটাল অবজেক্ট আইডেন্টিফায়ার (ডই)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "উন্মুক্ত প্রবেশাধিকারযুক্ত DOI সমাধানদাতা"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "পুনর্লিখিত DOI দ্বারা ব্যবহৃত সার্ভিস নির্বাচিত করুণ"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -13,7 +13,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: bo\n"
|
||||
@@ -579,15 +579,107 @@ msgstr ""
|
||||
msgid "Error loading the next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།ཁྱེད་ཀྱིས་གདམ་ཀ་ལ་བཅོས་སྒྲིག་གཏོང་རོགས།"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "འཚོལ་བཤེར་ལ་ནོར་འཁྲུལ་བྱུང་།"
|
||||
|
||||
@@ -784,11 +876,12 @@ msgid ""
|
||||
" page"
|
||||
msgstr "དྲ་ངོས་མར་འདྲུད་ནས་ཞབས་ལ་སླེབས་དུས་རང་འགུལ་སྒོས་འཕྲོ་མའི་ནང་དོན་འཆར་པར་བྱེད།"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr ""
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1394,16 +1487,8 @@ msgstr ""
|
||||
msgid "Preferences hash"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
@@ -2325,3 +2410,12 @@ msgstr "རྙན་ཟློས་སྦས།"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr ""
|
||||
|
||||
|
||||
Binary file not shown.
@@ -31,7 +31,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-09-19 15:25+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: ca\n"
|
||||
@@ -597,15 +597,107 @@ msgstr "Origen"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "S'ha produït un error en carregar la següent pàgina"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "La configuració no és vàlida, editeu-la"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "La configuració no és vàlida"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "error de cerca"
|
||||
|
||||
@@ -811,11 +903,12 @@ msgstr ""
|
||||
"Carrega automàticament la pàgina següent en desplaçar-se al final de la "
|
||||
"pàgina actual"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "Reescriptura de l'Open Access DOI"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1433,17 +1526,9 @@ msgstr "Inserta el hash de preferències copiat (sense URL) per restaurar"
|
||||
msgid "Preferences hash"
|
||||
msgstr "Hash de preferències"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "Identificador d'objecte digital (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Resolució del DOI"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "Selecciona el servei utilitzat per a la reescriptura del DOI"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2454,3 +2539,12 @@ msgstr "oculta el vídeo"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Cercador"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "Identificador d'objecte digital (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Resolució del DOI"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "Selecciona el servei utilitzat per a la reescriptura del DOI"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -27,8 +27,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"PO-Revision-Date: 2026-09-22 13:25+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-10-10 22:27+0000\n"
|
||||
"Last-Translator: Fjuro <fjuro@noreply.codeberg.org>\n"
|
||||
"Language: cs\n"
|
||||
"Language-Team: Czech <https://translate.codeberg.org/projects/searxng/"
|
||||
@@ -39,7 +39,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.18.0\n"
|
||||
"X-Generator: Weblate 2026.9.1\n"
|
||||
"X-Generator: Weblate 2026.10.1\n"
|
||||
|
||||
#. CONSTANT_NAMES['NO_SUBGROUPING']
|
||||
#: searx/searxng.msg
|
||||
@@ -595,15 +595,107 @@ msgstr "zdroj"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "Chyba při načítání další stránky"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr "zavřít"
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr "Jak se pohybovat v SearXNG pomocí klávesových zkratek"
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr "Ovládání"
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr "Výsledky"
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr "Navigace"
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr "Ostatní"
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr "odebrat zaměření ze zaměřeného vstupu"
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr "zkopírovat adresu zvoleného výsledku do schránky"
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr "přepnout okno nápovědy"
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr "zaměřit na vyhledávací pole"
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr "přejít na další stránku"
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr "otevřít výsledek vyhledávání"
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr "přejít na předchozí stránku"
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr "znovu načíst stránku ze serveru"
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr "otevřít výsledek v novém panelu"
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr "zvolit předchozí výsledek vyhledávání"
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr "zvolit další výsledek vyhledávání"
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr "posunout o stránku nahoru"
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr "posunout o půl stránky dolů"
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr "posunout o stránku dolů"
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr "posunout na vršek stránky"
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr "posunout o půl stránky nahoru"
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr "posunout na spodek stránky"
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "Neplatné nastavení, upravte své předvolby"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "Neplatné nastavení"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "chyba vyhledávání"
|
||||
|
||||
@@ -811,11 +903,12 @@ msgid ""
|
||||
" page"
|
||||
msgstr "Automaticky načte další stránku při posunutí na konec aktuální stránky"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "Přesměrování na Open Access DOI"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1436,17 +1529,9 @@ msgstr "Pro obnovení vložte zkopírovaný hash předvoleb (bez adresy URL)"
|
||||
msgid "Preferences hash"
|
||||
msgstr "Hash předvoleb"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "Digital Object Identifier (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Web pro přesměrování na Open Access DOI"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "Výběr služby použité při přepisu DOI"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr "Resolver DOI"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2440,3 +2525,12 @@ msgstr "skrýt video"
|
||||
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Vyhledávač"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "Digital Object Identifier (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Web pro přesměrování na Open Access DOI"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "Výběr služby použité při přepisu DOI"
|
||||
|
||||
Binary file not shown.
@@ -20,7 +20,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-05-19 12:07+0000\n"
|
||||
"Last-Translator: return42 <return42@noreply.codeberg.org>\n"
|
||||
"Language: cy\n"
|
||||
@@ -587,15 +587,107 @@ msgstr "Ffynhonnell"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "Gwall wrth lwytho'r dudalen nesaf"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "Gosodiadau annilys, golygwch eich dewisiadau"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "Gosodiadau annilys"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "gwall chwilio"
|
||||
|
||||
@@ -802,11 +894,12 @@ msgstr ""
|
||||
"Llwytho'r dudalen nesaf yn awtomatig wrth gyrraedd gwaelod y dudalen "
|
||||
"bresennol"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "Disodli DOI Open Access"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1422,18 +1515,10 @@ msgstr "Rhowch hash dewisiadau yma (heb URL) i'w adfer"
|
||||
msgid "Preferences hash"
|
||||
msgstr "Hash dewisiadau"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Atebydd DOI Open Access"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "Dewis y gwasanaeth i'r disodlydd DOI ddefnyddio"
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
"This tab does not exist in the user interface, but you can search with "
|
||||
@@ -2393,3 +2478,12 @@ msgstr "cuddio'r fideo"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Peiriant"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr ""
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Atebydd DOI Open Access"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "Dewis y gwasanaeth i'r disodlydd DOI ddefnyddio"
|
||||
|
||||
|
||||
Binary file not shown.
@@ -19,7 +19,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: searx\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2026-09-21 12:54+0000\n"
|
||||
"POT-Creation-Date: 2026-10-09 19:03+0000\n"
|
||||
"PO-Revision-Date: 2026-06-16 07:07+0000\n"
|
||||
"Last-Translator: AndersNordh <andersnordh@noreply.codeberg.org>\n"
|
||||
"Language: da\n"
|
||||
@@ -585,15 +585,107 @@ msgstr "Kilde"
|
||||
msgid "Error loading the next page"
|
||||
msgstr "Fejl ved indlæsning af den næste side"
|
||||
|
||||
#: searx/webapp.py:478 searx/webapp.py:878
|
||||
#: searx/webapp.py:332
|
||||
msgid "close"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:333
|
||||
msgid "How to navigate SearXNG with hotkeys"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:334
|
||||
msgid "Control"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:335
|
||||
msgid "Results"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:336
|
||||
msgid "Navigation"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:337
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:338
|
||||
msgid "remove focus from the focused input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:339
|
||||
msgid "copy url of the selected result to the clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:340
|
||||
msgid "toggle help window"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:341
|
||||
msgid "focus on the search input"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:342
|
||||
msgid "go to next page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:343
|
||||
msgid "open search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:344
|
||||
msgid "go to previous page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:345
|
||||
msgid "reload page from the server"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:346
|
||||
msgid "open the result in a new tab"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:347
|
||||
msgid "select previous search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:348
|
||||
msgid "select next search result"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:349
|
||||
msgid "scroll one page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:350
|
||||
msgid "scroll half a page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:351
|
||||
msgid "scroll one page down"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:352
|
||||
msgid "scroll to the top of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:353
|
||||
msgid "scroll half a page up"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:354
|
||||
msgid "scroll to the bottom of the page"
|
||||
msgstr ""
|
||||
|
||||
#: searx/webapp.py:502 searx/webapp.py:902
|
||||
msgid "Invalid settings, please edit your preferences"
|
||||
msgstr "Ugyldige indstillinger, redigér venligst dine valg"
|
||||
|
||||
#: searx/webapp.py:494
|
||||
#: searx/webapp.py:518
|
||||
msgid "Invalid settings"
|
||||
msgstr "Ugyldig indstilling"
|
||||
|
||||
#: searx/webapp.py:570 searx/webapp.py:660
|
||||
#: searx/webapp.py:594 searx/webapp.py:684
|
||||
msgid "search error"
|
||||
msgstr "søgefejl"
|
||||
|
||||
@@ -804,11 +896,12 @@ msgstr ""
|
||||
"ndlæser automatisk næste side, når du scroller til bunden af den aktuelle"
|
||||
" side"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:54
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
msgid "Open Access DOI rewrite"
|
||||
msgstr "Open Access DOI-omskrivning"
|
||||
|
||||
#: searx/plugins/oa_doi_rewrite.py:55
|
||||
#: searx/plugins/oa_doi_rewrite.py:56
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:15
|
||||
msgid ""
|
||||
"Avoid paywalls by redirecting to open-access versions of publications "
|
||||
"when available"
|
||||
@@ -1430,17 +1523,9 @@ msgstr "Indsæt kopieret indstillinger-hash (uden URL) for at gendanne"
|
||||
msgid "Preferences hash"
|
||||
msgstr "Præference hash"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:1
|
||||
msgid "Digital Object Identifier (DOI)"
|
||||
msgstr "Digital Object Identifier (DOI)"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:6
|
||||
msgid "Open Access DOI resolver"
|
||||
msgstr "Open Access DOI-forløser"
|
||||
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:18
|
||||
msgid "Select service used by DOI rewrite"
|
||||
msgstr "Vælg service brugt af DOI-omskrivning"
|
||||
#: searx/templates/simple/preferences/doi_resolver.html:2
|
||||
msgid "DOI Resolver"
|
||||
msgstr ""
|
||||
|
||||
#: searx/templates/simple/preferences/engines.html:9
|
||||
msgid ""
|
||||
@@ -2449,3 +2534,12 @@ msgstr "skjul video"
|
||||
#~ msgid "Engine"
|
||||
#~ msgstr "Maskine"
|
||||
|
||||
#~ msgid "Digital Object Identifier (DOI)"
|
||||
#~ msgstr "Digital Object Identifier (DOI)"
|
||||
|
||||
#~ msgid "Open Access DOI resolver"
|
||||
#~ msgstr "Open Access DOI-forløser"
|
||||
|
||||
#~ msgid "Select service used by DOI rewrite"
|
||||
#~ msgstr "Vælg service brugt af DOI-omskrivning"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user