summaryrefslogtreecommitdiff
path: root/searx
diff options
context:
space:
mode:
authorvojkovic <git@vojk.au>2026-07-16 21:12:03 +0000
committerBrock Vojkovic <brock@vojk.au>2026-08-01 11:09:50 +0800
commit8892414dc38dd57728b7f62f33152ea80e3b305f (patch)
tree9653d39889c7f17bee3185b5cf570215b2128388 /searx
parent6bfd82705a545a1535e36d0903fafe26c669a0fe (diff)
[feat] add kagi favicon resolver
Diffstat (limited to 'searx')
-rw-r--r--searx/favicons/favicons.toml1
-rw-r--r--searx/favicons/resolvers.py18
-rw-r--r--searx/settings.yml2
3 files changed, 19 insertions, 2 deletions
diff --git a/searx/favicons/favicons.toml b/searx/favicons/favicons.toml
index 0e433d3aa..c4a9f4d79 100644
--- a/searx/favicons/favicons.toml
+++ b/searx/favicons/favicons.toml
@@ -13,6 +13,7 @@ cfg_schema = 1 # config's schema version no.
# "duckduckgo" = "searx.favicons.resolvers.duckduckgo"
# "allesedv" = "searx.favicons.resolvers.allesedv"
# "google" = "searx.favicons.resolvers.google"
+# "kagi" = "searx.favicons.resolvers.kagi"
# "yandex" = "searx.favicons.resolvers.yandex"
[favicons.cache]
diff --git a/searx/favicons/resolvers.py b/searx/favicons/resolvers.py
index 1c9e192b6..8007330b3 100644
--- a/searx/favicons/resolvers.py
+++ b/searx/favicons/resolvers.py
@@ -7,7 +7,7 @@ timeout``) and returns a tuple ``(data, mime)``.
"""
-__all__ = ["DEFAULT_RESOLVER_MAP", "allesedv", "duckduckgo", "google", "yandex"]
+__all__ = ["DEFAULT_RESOLVER_MAP", "allesedv", "duckduckgo", "google", "kagi", "yandex"]
from typing import Callable
from searx import network
@@ -76,6 +76,21 @@ def google(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
return data, mime
+def kagi(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
+ """Favicon Resolver from kagi.com / https://news.kagi.com/api/favicon-proxy"""
+ data, mime = (None, None)
+ # quality can be either 'fast' or 'best', best is slower and can return svgs (e.g. github.com)
+ url = f"https://news.kagi.com/api/favicon-proxy?domain={domain}&quality=fast"
+ logger.debug("fetch favicon from: %s", url)
+
+ # will return a 404 if the favicon does not exist and a 200 if it does,
+ response = network.get(url, **_req_args(timeout=timeout))
+ if response and response.status_code == 200:
+ mime = response.headers['Content-Type']
+ data = response.content
+ return data, mime
+
+
def yandex(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
"""Favicon Resolver from yandex.com"""
data, mime = (None, None)
@@ -95,5 +110,6 @@ DEFAULT_RESOLVER_MAP = {
"allesedv": allesedv,
"duckduckgo": duckduckgo,
"google": google,
+ "kagi": kagi,
"yandex": yandex,
}
diff --git a/searx/settings.yml b/searx/settings.yml
index 8d615cb87..ad605f256 100644
--- a/searx/settings.yml
+++ b/searx/settings.yml
@@ -47,7 +47,7 @@ search:
# minimun characters to type before autocompleter starts
autocomplete_min: 4
# backend for the favicon near URL in search results.
- # Available resolvers: "allesedv", "duckduckgo", "google", "yandex" - leave blank to turn it off by default.
+ # Available resolvers: "allesedv", "duckduckgo", "google", "kagi", "yandex" - leave blank to turn it off by default.
favicon_resolver: ""
# Default search language - leave blank to detect from browser information or
# use codes from 'languages.py'