diff --git a/README.md b/README.md index 629bef1..5a84cf9 100644 --- a/README.md +++ b/README.md @@ -258,18 +258,20 @@ There are a few optional environment variables available for customizing a Whoog ### Config Environment Variables These environment variables allow setting default config values, but can be overwritten manually by using the home page config menu. These allow a shortcut for destroying/rebuilding an instance to the same config state every time. -| Variable | Description | -| ----------------------- | --------------------------------------------------------------- | -| WHOOGLE_CONFIG_COUNTRY | Filter results by hosting country | -| WHOOGLE_CONFIG_LANGUAGE | Set interface and search result language | -| WHOOGLE_CONFIG_DARK | Enable dark theme | -| WHOOGLE_CONFIG_SAFE | Enable safe searches | -| WHOOGLE_CONFIG_ALTS | Use social media site alternatives (nitter, invidious, etc) | -| WHOOGLE_CONFIG_TOR | Use Tor routing (if available) | -| WHOOGLE_CONFIG_NEW_TAB | Always open results in new tab | -| WHOOGLE_CONFIG_GET_ONLY | Search using GET requests only | -| WHOOGLE_CONFIG_URL | The root url of the instance (`https:///`) | -| WHOOGLE_CONFIG_STYLE | The custom CSS to use for styling (must be single line) | +| Variable | Description | +| ----------------------- | --------------------------------------------------------------- | +| WHOOGLE_CONFIG_COUNTRY | Filter results by hosting country | +| WHOOGLE_CONFIG_LANGUAGE | Set interface and search result language | +| WHOOGLE_CONFIG_DARK | Enable dark theme | +| WHOOGLE_CONFIG_SAFE | Enable safe searches | +| WHOOGLE_CONFIG_ALTS | Use social media site alternatives (nitter, invidious, etc) | +| WHOOGLE_CONFIG_TOR | Use Tor routing (if available) | +| WHOOGLE_CONFIG_NEW_TAB | Always open results in new tab | +| WHOOGLE_CONFIG_VIEW_IMAGE | Enable View Image option | +| WHOOGLE_CONFIG_GET_ONLY | Search using GET requests only | +| WHOOGLE_CONFIG_URL | The root url of the instance (`https:///`) | +| WHOOGLE_CONFIG_STYLE | The custom CSS to use for styling (must be single line) | + ## Usage Same as most search engines, with the exception of filtering by time range. diff --git a/app.json b/app.json index eb80f95..7a3e384 100644 --- a/app.json +++ b/app.json @@ -100,6 +100,11 @@ "value": "", "required": false }, + "WHOOGLE_CONFIG_VIEW_IMAGE": { + "description": "[CONFIG] Enable View Image option (set to 1 or leave blank)", + "value": "", + "required": false + }, "WHOOGLE_CONFIG_GET_ONLY": { "description": "[CONFIG] Search using GET requests only (set to 1 or leave blank)", "value": "", diff --git a/app/filter.py b/app/filter.py index 7848a79..4fede8a 100644 --- a/app/filter.py +++ b/app/filter.py @@ -254,3 +254,65 @@ class Filter: # Replace link destination link_desc[0].replace_with(get_site_alt(link_desc[0])) + + def view_image(self, soup) -> BeautifulSoup: + """Replaces the soup with a new one that handles mobile results and + adds the link of the image full res to the results. + + Args: + soup: A BeautifulSoup object containing the image mobile results. + + Returns: + BeautifulSoup: The new BeautifulSoup object + """ + + # get some tags that are unchanged between mobile and pc versions + search_input = soup.find_all('td', attrs={'class': "O4cRJf"})[0] + search_options = soup.find_all('div', attrs={'class': "M7pB2"})[0] + cor_suggested = soup.find_all('table', attrs={'class': "By0U9"}) + next_pages = soup.find_all('table', attrs={'class': "uZgmoc"})[0] + information = soup.find_all('div', attrs={'class': "TuS8Ad"})[0] + + results = [] + # find results div + results_div = soup.find_all('div', attrs={'class': "nQvrDb"})[0] + # find all the results + results_all = results_div.find_all('div', attrs={'class': "lIMUZd"}) + + for item in results_all: + urls = item.find('a')['href'].split('&imgrefurl=') + + img_url = urlparse.unquote(urls[0].replace('/imgres?imgurl=', '')) + webpage = urlparse.unquote(urls[1].split('&')[0]) + img_tbn = urlparse.unquote(item.find('a').find('img')['src']) + results.append({ + 'domain': urlparse.urlparse(webpage).netloc, + 'img_url': img_url, + 'webpage': webpage, + 'img_tbn': img_tbn + }) + + soup = BeautifulSoup(render_template('imageresults.html', + length=len(results), + results=results, + view_label="View Image"), + features='html.parser') + # replace search input object + soup.find_all('td', + attrs={'class': "O4cRJf"})[0].replaceWith(search_input) + # replace search options object (All, Images, Videos, etc.) + soup.find_all('div', + attrs={'class': "M7pB2"})[0].replaceWith(search_options) + # replace correction suggested by google object if exists + if len(cor_suggested): + soup.find_all( + 'table', + attrs={'class': "By0U9"} + )[0].replaceWith(cor_suggested[0]) + # replace next page object at the bottom of the page + soup.find_all('table', + attrs={'class': "uZgmoc"})[0].replaceWith(next_pages) + # replace information about user connection at the bottom of the page + soup.find_all('div', + attrs={'class': "TuS8Ad"})[0].replaceWith(information) + return soup diff --git a/app/models/config.py b/app/models/config.py index 8c83441..5a7082b 100644 --- a/app/models/config.py +++ b/app/models/config.py @@ -26,7 +26,9 @@ class Config: self.tor = read_config_bool('WHOOGLE_CONFIG_TOR') self.near = os.getenv('WHOOGLE_CONFIG_NEAR', '') self.new_tab = read_config_bool('WHOOGLE_CONFIG_NEW_TAB') + self.view_image = read_config_bool('WHOOGLE_CONFIG_VIEW_IMAGE') self.get_only = read_config_bool('WHOOGLE_CONFIG_GET_ONLY') + self.safe_keys = [ 'lang_search', 'lang_interface', diff --git a/app/request.py b/app/request.py index b4c67dd..91abdc0 100644 --- a/app/request.py +++ b/app/request.py @@ -146,6 +146,8 @@ class Request: self.language = config.lang_search self.mobile = 'Android' in normal_ua or 'iPhone' in normal_ua self.modified_user_agent = gen_user_agent(self.mobile) + if not self.mobile: + self.modified_user_agent_mobile = gen_user_agent(True) # Set up proxy, if previously configured if os.environ.get('WHOOGLE_PROXY_LOC'): @@ -192,7 +194,8 @@ class Request: return [_.attrib['data'] for _ in root.findall('.//suggestion/[@data]')] - def send(self, base_url=SEARCH_URL, query='', attempt=0) -> Response: + def send(self, base_url=SEARCH_URL, query='', attempt=0, + force_mobile=False) -> Response: """Sends an outbound request to a URL. Optionally sends the request using Tor, if enabled by the user. @@ -206,8 +209,13 @@ class Request: Response: The Response object returned by the requests call """ + if force_mobile and not self.mobile: + modified_user_agent = self.modified_user_agent_mobile + else: + modified_user_agent = self.modified_user_agent + headers = { - 'User-Agent': self.modified_user_agent + 'User-Agent': modified_user_agent } # FIXME: Should investigate this further to ensure the consent diff --git a/app/templates/imageresults.html b/app/templates/imageresults.html new file mode 100644 index 0000000..17ee98a --- /dev/null +++ b/app/templates/imageresults.html @@ -0,0 +1,116 @@ + + + + + + + + + + + +
+
+ + Google + +
+
+
+ + + + + + + + + + +
+ +
+
+
+
+ +
+
+ +
+
+
+
+ + +
+
+
+
+ + {% for i in range((length // 4) + 1) %} + + {% for j in range([length - (i*4), 4]|min) %} + + {% endfor %} + + {% endfor %} +
+ +
+
+ + +
+
+
+ +
+
+ + diff --git a/app/templates/index.html b/app/templates/index.html index 336b159..ee7cd2b 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -118,6 +118,12 @@
+
+ + +
— Adds the "View Image" option to image search results. + Note: This will cause image result thumbnails to be lower resolution.
+
diff --git a/app/utils/search.py b/app/utils/search.py index b71e6dd..c099b4c 100644 --- a/app/utils/search.py +++ b/app/utils/search.py @@ -120,11 +120,23 @@ class Search: self.request_params, self.config, content_filter.near) - get_body = g.user_request.send(query=full_query) + + # force mobile search when view image is true and + # the request is not already made by a mobile + view_image = ('tbm=isch' in full_query + and self.config.view_image + and not g.user_request.mobile) + + get_body = g.user_request.send(query=full_query, + force_mobile=view_image) # Produce cleanable html soup from response html_soup = bsoup(content_filter.reskin(get_body.text), 'html.parser') + # Replace current soup if view_image is active + if view_image: + html_soup = content_filter.view_image(html_soup) + # Indicate whether or not a Tor connection is active tor_banner = bsoup('', 'html.parser') if g.user_request.tor_valid: diff --git a/whoogle.env b/whoogle.env index 87a77a2..0fdfd74 100644 --- a/whoogle.env +++ b/whoogle.env @@ -20,6 +20,7 @@ #WHOOGLE_CONFIG_ALTS=1 # Use social media site alternatives #WHOOGLE_CONFIG_TOR=1 # Use Tor if available #WHOOGLE_CONFIG_NEW_TAB=1 # Open results in new tab +#WHOOGLE_CONFIG_VIEW_IMAGE=1 # Enable View Image option #WHOOGLE_CONFIG_GET_ONLY=1 # Search using GET requests only #WHOOGLE_CONFIG_URL=https:/// #WHOOGLE_CONFIG_STYLE=":root { /* LIGHT THEME COLORS */ --whoogle-background: #d8dee9; --whoogle-accent: #2e3440; --whoogle-text: #3B4252; --whoogle-contrast-text: #eceff4; --whoogle-secondary-text: #70757a; --whoogle-result-bg: #fff; --whoogle-result-title: #4c566a; --whoogle-result-url: #81a1c1; --whoogle-result-visited: #a3be8c; /* DARK THEME COLORS */ --whoogle-dark-background: #222; --whoogle-dark-accent: #685e79; --whoogle-dark-text: #fff; --whoogle-dark-contrast-text: #000; --whoogle-dark-secondary-text: #bbb; --whoogle-dark-result-bg: #000; --whoogle-dark-result-title: #1967d2; --whoogle-dark-result-url: #4b11a8; --whoogle-dark-result-visited: #bbbbff; }"