From 4292ec7f636d51a5a150c094819a88db16c42627 Mon Sep 17 00:00:00 2001 From: Ben Busby Date: Wed, 11 Oct 2023 10:49:04 -0600 Subject: [PATCH] Add icons for each search result This appends an icon element to each search result, using the result domain's "/favicon.ico" path. Note that some sites do not have a standard /favicon.ico, but have a unique path to a specifically sized favicon instead. Worse still, some sites use javascript to load their favicon, which would make it even more difficult for Whoogle to figure out. For now this approach is fine, but can be expanded upon in the future if desired. --- app/filter.py | 47 +++++++++++++++++++++++++++++++++++++++ app/static/css/search.css | 5 +++++ 2 files changed, 52 insertions(+) diff --git a/app/filter.py b/app/filter.py index eae60f8..19ce808 100644 --- a/app/filter.py +++ b/app/filter.py @@ -172,6 +172,7 @@ class Filter: for link in self.soup.find_all('a', href=True): self.update_link(link) + self.add_favicon(link) if self.config.alts: self.site_alt_swap() @@ -229,6 +230,52 @@ class Filter: d.string = str(div_soup) + def add_favicon(self, link) -> None: + """Adds icons for each returned result, using the result site's favicon + + Returns: + None (The soup object is modified directly) + """ + # Skip empty, parentless, or internal links + if not link or not link.parent or not link['href'].startswith('http'): + return + + parent = link.parent + is_result_div = False + + # Check each parent to make sure that the div doesn't already have a + # favicon attached, and that the div is a result div + while parent: + p_cls = parent.attrs.get('class') or [] + if 'has-favicon' in p_cls: + return + elif f'{GClasses.result_class_a}' not in p_cls: + parent = parent.parent + else: + is_result_div = True + break + + if not is_result_div: + return + + # Construct the html for inserting the icon into the parent div + parsed = urlparse.urlparse(link['href']) + src = f'{self.root_url}/{Endpoint.element}?url=' + ( + f'{parsed.scheme}://{parsed.netloc}/favicon.ico' + ) + '&type=image/x-icon' + html = f'' + + favicon = BeautifulSoup(html, 'html.parser') + link.parent.insert(0, favicon) + + # Update all parents to indicate that a favicon has been attached + parent = link.parent + while parent: + p_cls = parent.get('class') or [] + p_cls.append('has-favicon') + parent['class'] = p_cls + parent = parent.parent + def remove_site_blocks(self, soup) -> None: if not self.config.block or not soup.body: return diff --git a/app/static/css/search.css b/app/static/css/search.css index 121026a..748020f 100644 --- a/app/static/css/search.css +++ b/app/static/css/search.css @@ -58,6 +58,11 @@ details summary span { text-align: center; } +.site-favicon { + float: right; + width: 25px; +} + @media (min-width: 801px) { body { min-width: 736px !important;