.oO SearXNG Developer Documentation Oo.
Loading...
Searching...
No Matches
resolvers.py
Go to the documentation of this file.
1# SPDX-License-Identifier: AGPL-3.0-or-later
2"""Implementations of the favicon *resolvers* that are available in the favicon
3proxy by default. A *resolver* is a function that obtains the favicon from an
4external source. The *resolver* function receives two arguments (``domain,
5timeout``) and returns a tuple ``(data, mime)``.
6
7"""
8
9
10__all__ = ["DEFAULT_RESOLVER_MAP", "allesedv", "duckduckgo", "google", "yandex"]
11
12from typing import Callable
13from searx import network
14from searx import logger
15
16DEFAULT_RESOLVER_MAP: dict[str, Callable]
17logger = logger.getChild('favicons.resolvers')
18
19
20def _req_args(**kwargs):
21 # add the request arguments from the searx.network
22 d = {"raise_for_httperror": False}
23 d.update(kwargs)
24 return d
25
26
27def allesedv(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
28 """Favicon Resolver from allesedv.com / https://favicon.allesedv.com/"""
29 data, mime = (None, None)
30 url = f"https://f1.allesedv.com/32/{domain}"
31 logger.debug("fetch favicon from: %s", url)
32
33 # will just return a 200 regardless of the favicon existing or not
34 # sometimes will be correct size, sometimes not
35 response = network.get(url, **_req_args(timeout=timeout))
36 if response and response.status_code == 200:
37 mime = response.headers['Content-Type']
38 if mime != 'image/gif':
39 data = response.content
40 return data, mime
41
42
43def duckduckgo(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
44 """Favicon Resolver from duckduckgo.com / https://blog.jim-nielsen.com/2021/displaying-favicons-for-any-domain/"""
45 data, mime = (None, None)
46 url = f"https://icons.duckduckgo.com/ip2/{domain}.ico"
47 logger.debug("fetch favicon from: %s", url)
48
49 # will return a 404 if the favicon does not exist and a 200 if it does,
50 response = network.get(url, **_req_args(timeout=timeout))
51 if response and response.status_code == 200:
52 # api will respond with a 32x32 png image
53 mime = response.headers['Content-Type']
54 data = response.content
55 return data, mime
56
57
58def google(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
59 """Favicon Resolver from google.com"""
60 data, mime = (None, None)
61
62 # URL https://www.google.com/s2/favicons?sz=32&domain={domain}" will be
63 # redirected (HTTP 301 Moved Permanently) to t1.gstatic.com/faviconV2:
64 url = (
65 f"https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL"
66 f"&url=https://{domain}&size=32"
67 )
68 logger.debug("fetch favicon from: %s", url)
69
70 # will return a 404 if the favicon does not exist and a 200 if it does,
71 response = network.get(url, **_req_args(timeout=timeout))
72 if response and response.status_code == 200:
73 # api will respond with a 32x32 png image
74 mime = response.headers['Content-Type']
75 data = response.content
76 return data, mime
77
78
79def yandex(domain: str, timeout: int) -> tuple[None | bytes, None | str]:
80 """Favicon Resolver from yandex.com"""
81 data, mime = (None, None)
82 url = f"https://favicon.yandex.net/favicon/{domain}"
83 logger.debug("fetch favicon from: %s", url)
84
85 # api will respond with a 16x16 png image, if it doesn't exist, it will be a
86 # 1x1 png image (70 bytes)
87 response = network.get(url, **_req_args(timeout=timeout))
88 if response and response.status_code == 200 and len(response.content) > 70:
89 mime = response.headers['Content-Type']
90 data = response.content
91 return data, mime
92
93
94DEFAULT_RESOLVER_MAP = {
95 "allesedv": allesedv,
96 "duckduckgo": duckduckgo,
97 "google": google,
98 "yandex": yandex,
99}
tuple[None|bytes, None|str] google(str domain, int timeout)
Definition resolvers.py:58
tuple[None|bytes, None|str] yandex(str domain, int timeout)
Definition resolvers.py:79
tuple[None|bytes, None|str] allesedv(str domain, int timeout)
Definition resolvers.py:27
tuple[None|bytes, None|str] duckduckgo(str domain, int timeout)
Definition resolvers.py:43