Fetch fallback site icons from DDG

DDG provides favicons using the url format
icons.duckduckgo.com/ip2/{site}.ico

This can be used to fetch favicons in the event that the default
"/favicon.ico" path does not work.
main
Ben Busby 2023-10-11 17:26:12 -06:00
parent 81b7fd1876
commit 7bda165ca3
No known key found for this signature in database
GPG Key ID: B9B7231E01D924A1
2 changed files with 30 additions and 2 deletions

View File

@ -17,7 +17,8 @@ from app.models.config import Config
from app.models.endpoint import Endpoint from app.models.endpoint import Endpoint
from app.request import Request, TorError from app.request import Request, TorError
from app.utils.bangs import resolve_bang from app.utils.bangs import resolve_bang
from app.utils.misc import empty_gif, placeholder_img, get_proxy_host_url from app.utils.misc import empty_gif, placeholder_img, get_proxy_host_url, \
fetch_favicon
from app.filter import Filter from app.filter import Filter
from app.utils.misc import read_config_bool, get_client_ip, get_request_url, \ from app.utils.misc import read_config_bool, get_client_ip, get_request_url, \
check_for_update check_for_update
@ -493,7 +494,8 @@ def element():
# Display an empty gif if the requested element couldn't be retrieved # Display an empty gif if the requested element couldn't be retrieved
if response.status_code != 200 or len(response.content) == 0: if response.status_code != 200 or len(response.content) == 0:
if 'favicon' in src_url: if 'favicon' in src_url:
return send_file(io.BytesIO(placeholder_img), mimetype='image/png') favicon = fetch_favicon(src_url)
return send_file(io.BytesIO(favicon), mimetype='image/png')
else: else:
return send_file(io.BytesIO(empty_gif), mimetype='image/gif') return send_file(io.BytesIO(empty_gif), mimetype='image/gif')

View File

@ -2,11 +2,14 @@ import base64
from bs4 import BeautifulSoup as bsoup from bs4 import BeautifulSoup as bsoup
from flask import Request from flask import Request
import hashlib import hashlib
import io
import os import os
import re import re
from requests import exceptions, get from requests import exceptions, get
from urllib.parse import urlparse from urllib.parse import urlparse
ddg_favicon_site = 'http://icons.duckduckgo.com/ip2'
empty_gif = base64.b64decode( empty_gif = base64.b64decode(
'R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==') 'R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==')
@ -21,6 +24,29 @@ placeholder_img = base64.b64decode(
) )
def fetch_favicon(url: str) -> bytes:
"""Fetches a favicon using DuckDuckGo's favicon retriever
Args:
url: The url to fetch the favicon from
Returns:
bytes - the favicon bytes, or a placeholder image if one
was not returned
"""
domain = urlparse(url).netloc
response = get(f'{ddg_favicon_site}/{domain}.ico')
if response.status_code == 200 and len(response.content) > 0:
tmp_mem = io.BytesIO()
tmp_mem.write(response.content)
tmp_mem.seek(0)
return tmp_mem.read()
else:
return placeholder_img
def gen_file_hash(path: str, static_file: str) -> str: def gen_file_hash(path: str, static_file: str) -> str:
file_contents = open(os.path.join(path, static_file), 'rb').read() file_contents = open(os.path.join(path, static_file), 'rb').read()
file_hash = hashlib.md5(file_contents).hexdigest()[:8] file_hash = hashlib.md5(file_contents).hexdigest()[:8]