mirror of
https://github.com/searxng/searxng.git
synced 2024-11-22 12:10:11 +01:00
101 lines
3.6 KiB
Python
101 lines
3.6 KiB
Python
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||
|
"""Implementations of the favicon *resolvers* that are available in the favicon
|
||
|
proxy by default. A *resolver* is a function that obtains the favicon from an
|
||
|
external source. The *resolver* function receives two arguments (``domain,
|
||
|
timeout``) and returns a tuple ``(data, mime)``.
|
||
|
|
||
|
"""
|
||
|
|
||
|
from __future__ import annotations
|
||
|
|
||
|
__all__ = ["DEFAULT_RESOLVER_MAP", "allesedv", "duckduckgo", "google", "yandex"]
|
||
|
|
||
|
from typing import Callable
|
||
|
from searx import network
|
||
|
from searx import logger
|
||
|
|
||
|
DEFAULT_RESOLVER_MAP: dict[str, Callable]
|
||
|
logger = logger.getChild('favicons.resolvers')
|
||
|
|
||
|
|
||
|
def _req_args(**kwargs):
|
||
|
# add the request arguments from the searx.network
|
||
|
d = {"raise_for_httperror": False}
|
||
|
d.update(kwargs)
|
||
|
return d
|
||
|
|
||
|
|
||
|
def allesedv(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
|
||
|
"""Favicon Resolver from allesedv.com / https://favicon.allesedv.com/"""
|
||
|
data, mime = (None, None)
|
||
|
url = f"https://f1.allesedv.com/32/{domain}"
|
||
|
logger.debug("fetch favicon from: %s", url)
|
||
|
|
||
|
# will just return a 200 regardless of the favicon existing or not
|
||
|
# sometimes will be correct size, sometimes not
|
||
|
response = network.get(url, **_req_args(timeout=timeout))
|
||
|
if response and response.status_code == 200:
|
||
|
mime = response.headers['Content-Type']
|
||
|
if mime != 'image/gif':
|
||
|
data = response.content
|
||
|
return data, mime
|
||
|
|
||
|
|
||
|
def duckduckgo(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
|
||
|
"""Favicon Resolver from duckduckgo.com / https://blog.jim-nielsen.com/2021/displaying-favicons-for-any-domain/"""
|
||
|
data, mime = (None, None)
|
||
|
url = f"https://icons.duckduckgo.com/ip2/{domain}.ico"
|
||
|
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:
|
||
|
# api will respond with a 32x32 png image
|
||
|
mime = response.headers['Content-Type']
|
||
|
data = response.content
|
||
|
return data, mime
|
||
|
|
||
|
|
||
|
def google(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
|
||
|
"""Favicon Resolver from google.com"""
|
||
|
data, mime = (None, None)
|
||
|
|
||
|
# URL https://www.google.com/s2/favicons?sz=32&domain={domain}" will be
|
||
|
# redirected (HTTP 301 Moved Permanently) to t1.gstatic.com/faviconV2:
|
||
|
url = (
|
||
|
f"https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL"
|
||
|
f"&url=https://{domain}&size=32"
|
||
|
)
|
||
|
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:
|
||
|
# api will respond with a 32x32 png image
|
||
|
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)
|
||
|
url = f"https://favicon.yandex.net/favicon/{domain}"
|
||
|
logger.debug("fetch favicon from: %s", url)
|
||
|
|
||
|
# api will respond with a 16x16 png image, if it doesn't exist, it will be a
|
||
|
# 1x1 png image (70 bytes)
|
||
|
response = network.get(url, **_req_args(timeout=timeout))
|
||
|
if response and response.status_code == 200 and len(response.content) > 70:
|
||
|
mime = response.headers['Content-Type']
|
||
|
data = response.content
|
||
|
return data, mime
|
||
|
|
||
|
|
||
|
DEFAULT_RESOLVER_MAP = {
|
||
|
"allesedv": allesedv,
|
||
|
"duckduckgo": duckduckgo,
|
||
|
"google": google,
|
||
|
"yandex": yandex,
|
||
|
}
|