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.request import Request, TorError
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.utils.misc import read_config_bool, get_client_ip, get_request_url, \
check_for_update
@ -493,7 +494,8 @@ def element():
# Display an empty gif if the requested element couldn't be retrieved
if response.status_code != 200 or len(response.content) == 0:
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:
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 flask import Request
import hashlib
import io
import os
import re
from requests import exceptions, get
from urllib.parse import urlparse
ddg_favicon_site = 'http://icons.duckduckgo.com/ip2'
empty_gif = base64.b64decode(
'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:
file_contents = open(os.path.join(path, static_file), 'rb').read()
file_hash = hashlib.md5(file_contents).hexdigest()[:8]