Use consistent header for all result types (#535)
Introduces a header for switching between result types (i.e. "All", "News", etc) that is consistent between the different result types. Previously, image results had a tab header that was formatted in a drastically different manner, which was jarring when switching from a different result page to the Images page. Created a G class enum to reference class names returned in search results. As noted in the class doc, this should only be used/updated as a last resort, as class names change frequently. For some instances, such as replacing the tbm tab, it's a lot easier to just replace by header name than attempting to replace it based on how the element is structured. Also updated a few styles to revert the latest styling changes being applied by Google. Co-authored-by: jacr13 <ramos.joao@protonmail.com> Co-authored-by: Ben Busby <contact@benbusby.com>main
parent
4aa94a5d75
commit
11099f7b1d
|
@ -52,6 +52,9 @@ app.config['TRANSLATIONS'] = json.load(open(
|
||||||
app.config['THEMES'] = json.load(open(
|
app.config['THEMES'] = json.load(open(
|
||||||
os.path.join(app.config['STATIC_FOLDER'], 'settings/themes.json'),
|
os.path.join(app.config['STATIC_FOLDER'], 'settings/themes.json'),
|
||||||
encoding='utf-8'))
|
encoding='utf-8'))
|
||||||
|
app.config['HEADER_TABS'] = json.load(open(
|
||||||
|
os.path.join(app.config['STATIC_FOLDER'], 'settings/header_tabs.json'),
|
||||||
|
encoding='utf-8'))
|
||||||
app.config['CONFIG_PATH'] = os.getenv(
|
app.config['CONFIG_PATH'] = os.getenv(
|
||||||
'CONFIG_VOLUME',
|
'CONFIG_VOLUME',
|
||||||
os.path.join(app.config['STATIC_FOLDER'], 'config'))
|
os.path.join(app.config['STATIC_FOLDER'], 'config'))
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from app.models.config import Config
|
from app.models.config import Config
|
||||||
from app.models.endpoint import Endpoint
|
from app.models.endpoint import Endpoint
|
||||||
|
from app.models.g_classes import GClasses
|
||||||
from app.request import VALID_PARAMS, MAPS_URL
|
from app.request import VALID_PARAMS, MAPS_URL
|
||||||
from app.utils.misc import read_config_bool
|
from app.utils.misc import read_config_bool
|
||||||
from app.utils.results import *
|
from app.utils.results import *
|
||||||
|
@ -13,6 +14,15 @@ from urllib.parse import parse_qs
|
||||||
import os
|
import os
|
||||||
|
|
||||||
minimal_mode_sections = ['Top stories', 'Images', 'People also ask']
|
minimal_mode_sections = ['Top stories', 'Images', 'People also ask']
|
||||||
|
unsupported_g_pages = [
|
||||||
|
'support.google.com',
|
||||||
|
'accounts.google.com',
|
||||||
|
'policies.google.com',
|
||||||
|
'google.com/preferences',
|
||||||
|
'google.com/intl',
|
||||||
|
'advanced_search',
|
||||||
|
'tbm=shop'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def extract_q(q_str: str, href: str) -> str:
|
def extract_q(q_str: str, href: str) -> str:
|
||||||
|
@ -80,6 +90,7 @@ class Filter:
|
||||||
self.remove_block_url()
|
self.remove_block_url()
|
||||||
self.collapse_sections()
|
self.collapse_sections()
|
||||||
self.update_styling(soup)
|
self.update_styling(soup)
|
||||||
|
self.remove_block_tabs(soup)
|
||||||
|
|
||||||
for img in [_ for _ in soup.find_all('img') if 'src' in _.attrs]:
|
for img in [_ for _ in soup.find_all('img') if 'src' in _.attrs]:
|
||||||
self.update_element_src(img, 'image/png')
|
self.update_element_src(img, 'image/png')
|
||||||
|
@ -143,6 +154,21 @@ class Filter:
|
||||||
if block_url.search(_.attrs['href']) is not None]
|
if block_url.search(_.attrs['href']) is not None]
|
||||||
_ = div.decompose() if len(block_divs) else None
|
_ = div.decompose() if len(block_divs) else None
|
||||||
|
|
||||||
|
def remove_block_tabs(self, soup) -> None:
|
||||||
|
if self.main_divs:
|
||||||
|
for div in self.main_divs.find_all(
|
||||||
|
'div',
|
||||||
|
attrs={'class': f'{GClasses.main_tbm_tab}'}
|
||||||
|
):
|
||||||
|
_ = div.decompose()
|
||||||
|
else:
|
||||||
|
# when in images tab
|
||||||
|
for div in soup.find_all(
|
||||||
|
'div',
|
||||||
|
attrs={'class': f'{GClasses.images_tbm_tab}'}
|
||||||
|
):
|
||||||
|
_ = div.decompose()
|
||||||
|
|
||||||
def collapse_sections(self) -> None:
|
def collapse_sections(self) -> None:
|
||||||
"""Collapses long result sections ("people also asked", "related
|
"""Collapses long result sections ("people also asked", "related
|
||||||
searches", etc) into "details" elements
|
searches", etc) into "details" elements
|
||||||
|
@ -273,6 +299,26 @@ class Filter:
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Fix body max width on images tab
|
||||||
|
style = soup.find('style')
|
||||||
|
div = soup.find('div', attrs={'class': f'{GClasses.images_tbm_tab}'})
|
||||||
|
if style and div and not self.mobile:
|
||||||
|
css = style.string
|
||||||
|
css_html_tag = (
|
||||||
|
'html{'
|
||||||
|
'font-family: Roboto, Helvetica Neue, Arial, sans-serif;'
|
||||||
|
'font-size: 14px;'
|
||||||
|
'line-height: 20px;'
|
||||||
|
'text-size-adjust: 100%;'
|
||||||
|
'word-wrap: break-word;'
|
||||||
|
'}'
|
||||||
|
)
|
||||||
|
css = f"{css_html_tag}{css}"
|
||||||
|
css = re.sub('body{(.*?)}',
|
||||||
|
'body{padding:0 8px;margin:0 auto;max-width:736px;}',
|
||||||
|
css)
|
||||||
|
style.string = css
|
||||||
|
|
||||||
def update_link(self, link: Tag) -> None:
|
def update_link(self, link: Tag) -> None:
|
||||||
"""Update internal link paths with encrypted path, otherwise remove
|
"""Update internal link paths with encrypted path, otherwise remove
|
||||||
unnecessary redirects and/or marketing params from the url
|
unnecessary redirects and/or marketing params from the url
|
||||||
|
@ -284,14 +330,15 @@ class Filter:
|
||||||
None (the tag is updated directly)
|
None (the tag is updated directly)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Replace href with only the intended destination (no "utm" type tags)
|
# Remove any elements that direct to unsupported Google pages
|
||||||
href = link['href'].replace('https://www.google.com', '')
|
if any(url in link['href'] for url in unsupported_g_pages):
|
||||||
if 'advanced_search' in href or 'tbm=shop' in href:
|
|
||||||
# FIXME: The "Shopping" tab requires further filtering (see #136)
|
# FIXME: The "Shopping" tab requires further filtering (see #136)
|
||||||
# Temporarily removing all links to that tab for now.
|
# Temporarily removing all links to that tab for now.
|
||||||
link.decompose()
|
link.decompose()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Replace href with only the intended destination (no "utm" type tags)
|
||||||
|
href = link['href'].replace('https://www.google.com', '')
|
||||||
result_link = urlparse.urlparse(href)
|
result_link = urlparse.urlparse(href)
|
||||||
q = extract_q(result_link.query, href)
|
q = extract_q(result_link.query, href)
|
||||||
|
|
||||||
|
@ -362,11 +409,8 @@ class Filter:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# get some tags that are unchanged between mobile and pc versions
|
# 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"})
|
cor_suggested = soup.find_all('table', attrs={'class': "By0U9"})
|
||||||
next_pages = soup.find_all('table', attrs={'class': "uZgmoc"})[0]
|
next_pages = soup.find_all('table', attrs={'class': "uZgmoc"})[0]
|
||||||
information = soup.find_all('div', attrs={'class': "TuS8Ad"})[0]
|
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
# find results div
|
# find results div
|
||||||
|
@ -404,12 +448,7 @@ class Filter:
|
||||||
results=results,
|
results=results,
|
||||||
view_label="View Image"),
|
view_label="View Image"),
|
||||||
features='html.parser')
|
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
|
# replace correction suggested by google object if exists
|
||||||
if len(cor_suggested):
|
if len(cor_suggested):
|
||||||
soup.find_all(
|
soup.find_all(
|
||||||
|
@ -419,7 +458,4 @@ class Filter:
|
||||||
# replace next page object at the bottom of the page
|
# replace next page object at the bottom of the page
|
||||||
soup.find_all('table',
|
soup.find_all('table',
|
||||||
attrs={'class': "uZgmoc"})[0].replaceWith(next_pages)
|
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
|
return soup
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class GClasses(Enum):
|
||||||
|
"""A class for tracking obfuscated class names used in Google results that
|
||||||
|
are directly referenced in Whoogle's filtering code.
|
||||||
|
|
||||||
|
Note: Using these should be a last resort. It is always preferred to filter
|
||||||
|
results using structural cues instead of referencing class names, as these
|
||||||
|
are liable to change at any moment.
|
||||||
|
"""
|
||||||
|
main_tbm_tab = 'KP7LCb'
|
||||||
|
images_tbm_tab = 'n692Zd'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.value
|
|
@ -1,6 +1,7 @@
|
||||||
import argparse
|
import argparse
|
||||||
import base64
|
import base64
|
||||||
import io
|
import io
|
||||||
|
import os
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import pickle
|
import pickle
|
||||||
|
@ -17,14 +18,15 @@ 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 read_config_bool, get_client_ip, get_request_url
|
from app.utils.misc import read_config_bool, get_client_ip, get_request_url
|
||||||
from app.utils.results import add_ip_card, bold_search_terms,\
|
from app.utils.results import add_ip_card, bold_search_terms,\
|
||||||
add_currency_card, check_currency
|
add_currency_card, check_currency, get_tabs_content
|
||||||
from app.utils.search import *
|
from app.utils.search import Search, needs_https, has_captcha
|
||||||
from app.utils.session import generate_user_key, valid_user_session
|
from app.utils.session import generate_user_key, valid_user_session
|
||||||
from bs4 import BeautifulSoup as bsoup
|
from bs4 import BeautifulSoup as bsoup
|
||||||
from flask import jsonify, make_response, request, redirect, render_template, \
|
from flask import jsonify, make_response, request, redirect, render_template, \
|
||||||
send_file, session, url_for
|
send_file, session, url_for, g
|
||||||
from requests import exceptions, get
|
from requests import exceptions, get
|
||||||
from requests.models import PreparedRequest
|
from requests.models import PreparedRequest
|
||||||
|
from cryptography.fernet import Fernet
|
||||||
|
|
||||||
# Load DDG bang json files only on init
|
# Load DDG bang json files only on init
|
||||||
bang_json = json.load(open(app.config['BANG_FILE'])) or {}
|
bang_json = json.load(open(app.config['BANG_FILE'])) or {}
|
||||||
|
@ -347,6 +349,12 @@ def search():
|
||||||
html_soup = bsoup(str(response), 'html.parser')
|
html_soup = bsoup(str(response), 'html.parser')
|
||||||
response = add_ip_card(html_soup, get_client_ip(request))
|
response = add_ip_card(html_soup, get_client_ip(request))
|
||||||
|
|
||||||
|
# Update tabs content
|
||||||
|
tabs = get_tabs_content(app.config['HEADER_TABS'],
|
||||||
|
search_util.full_query,
|
||||||
|
search_util.search_type,
|
||||||
|
translation)
|
||||||
|
|
||||||
# Feature to display currency_card
|
# Feature to display currency_card
|
||||||
conversion = check_currency(str(response))
|
conversion = check_currency(str(response))
|
||||||
if conversion:
|
if conversion:
|
||||||
|
@ -373,15 +381,14 @@ def search():
|
||||||
) and not search_util.search_type, # Standard search queries only
|
) and not search_util.search_type, # Standard search queries only
|
||||||
response=response,
|
response=response,
|
||||||
version_number=app.config['VERSION_NUMBER'],
|
version_number=app.config['VERSION_NUMBER'],
|
||||||
search_header=(render_template(
|
search_header=render_template(
|
||||||
'header.html',
|
'header.html',
|
||||||
config=g.user_config,
|
config=g.user_config,
|
||||||
logo=render_template('logo.html', dark=g.user_config.dark),
|
logo=render_template('logo.html', dark=g.user_config.dark),
|
||||||
query=urlparse.unquote(query),
|
query=urlparse.unquote(query),
|
||||||
search_type=search_util.search_type,
|
search_type=search_util.search_type,
|
||||||
mobile=g.user_request.mobile)
|
mobile=g.user_request.mobile,
|
||||||
if 'isch' not in
|
tabs=tabs))
|
||||||
search_util.search_type else '')), 200
|
|
||||||
|
|
||||||
|
|
||||||
@app.route(f'/{Endpoint.config}', methods=['GET', 'POST', 'PUT'])
|
@app.route(f'/{Endpoint.config}', methods=['GET', 'POST', 'PUT'])
|
||||||
|
|
|
@ -74,6 +74,7 @@ select {
|
||||||
|
|
||||||
.ZINbbc.luh4tb {
|
.ZINbbc.luh4tb {
|
||||||
background: var(--whoogle-dark-result-bg) !important;
|
background: var(--whoogle-dark-result-bg) !important;
|
||||||
|
margin-bottom: 24px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bRsWnc {
|
.bRsWnc {
|
||||||
|
@ -204,3 +205,7 @@ path {
|
||||||
.cb:focus {
|
.cb:focus {
|
||||||
color: var(--whoogle-dark-contrast-text) !important;
|
color: var(--whoogle-dark-contrast-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desktop-header, .mobile-header {
|
||||||
|
background-color: var(--whoogle-dark-result-bg) !important;
|
||||||
|
}
|
||||||
|
|
|
@ -98,6 +98,11 @@ header {
|
||||||
border: 0px !important;
|
border: 0px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.autocomplete-mobile{
|
||||||
|
display: -webkit-box;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.desktop-header-logo {
|
.desktop-header-logo {
|
||||||
height: 1.65em;
|
height: 1.65em;
|
||||||
}
|
}
|
||||||
|
@ -106,3 +111,113 @@ header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1
|
flex: 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #1967D2;
|
||||||
|
text-decoration: none;
|
||||||
|
tap-highlight-color: rgba(0, 0, 0, .10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tab-div {
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
box-shadow: 0 2px 3px rgba(32, 33, 36, 0.18);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tab-div-2 {
|
||||||
|
border-top: 1px solid #dadce0;
|
||||||
|
height: 39px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tab-div-3 {
|
||||||
|
height: 51px;
|
||||||
|
overflow-x: auto;
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-header {
|
||||||
|
height: 39px;
|
||||||
|
display: box;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tab {
|
||||||
|
box-pack: justify;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 37px;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-header a, .desktop-header span {
|
||||||
|
color: #70757a;
|
||||||
|
display: block;
|
||||||
|
flex: none;
|
||||||
|
padding: 0 16px;
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.header-tab-span {
|
||||||
|
border-bottom: 2px solid #4285f4;
|
||||||
|
color: #4285f4;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header {
|
||||||
|
height: 39px;
|
||||||
|
display: box;
|
||||||
|
display: flex;
|
||||||
|
overflow-x: scroll;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mobile-header a, .mobile-header span {
|
||||||
|
color: #70757a;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
/* padding: 8px 12px 8px 12px; */
|
||||||
|
}
|
||||||
|
|
||||||
|
span.mobile-tab-span {
|
||||||
|
border-bottom: 2px solid #202124;
|
||||||
|
color: #202124;
|
||||||
|
height: 26px;
|
||||||
|
/* margin: 0 12px; */
|
||||||
|
/* padding: 0; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-header input {
|
||||||
|
margin: 2px 4px 2px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.header-tab-a:visited {
|
||||||
|
color: #70757a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-tab-div-end {
|
||||||
|
border-left: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-bar-input {
|
||||||
|
display: block;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 0 0 0 8px;
|
||||||
|
flex: 1;
|
||||||
|
height: 35px;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
width: 100%;
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 801px) {
|
||||||
|
.header-tab-div {
|
||||||
|
margin-bottom: 10px !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,8 @@ select {
|
||||||
|
|
||||||
.ZINbbc.luh4tb {
|
.ZINbbc.luh4tb {
|
||||||
background: var(--whoogle-result-bg) !important;
|
background: var(--whoogle-result-bg) !important;
|
||||||
|
box-shadow: 0 1px 6px rgba(32,33,36,0.28) !important;
|
||||||
|
margin-bottom: 24px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bRsWnc {
|
.bRsWnc {
|
||||||
|
@ -190,3 +192,7 @@ path {
|
||||||
.cb:focus {
|
.cb:focus {
|
||||||
color: var(--whoogle-text) !important;
|
color: var(--whoogle-text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desktop-header, .mobile-header {
|
||||||
|
background-color: var(--whoogle-result-bg) !important;
|
||||||
|
}
|
||||||
|
|
|
@ -31,8 +31,9 @@ body {
|
||||||
}
|
}
|
||||||
|
|
||||||
details summary {
|
details summary {
|
||||||
padding: 10px;
|
margin-bottom: 20px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
details summary span {
|
details summary span {
|
||||||
|
@ -53,8 +54,18 @@ details summary span {
|
||||||
padding-top: 0 !important;
|
padding-top: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
@media (min-width: 801px) {
|
@media (min-width: 801px) {
|
||||||
body {
|
body {
|
||||||
min-width: 736px !important;
|
min-width: 736px !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 801px) {
|
||||||
|
details summary {
|
||||||
|
margin-bottom: 10px !important
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"all": {
|
||||||
|
"tbm": null,
|
||||||
|
"href": "search?q={query}",
|
||||||
|
"name": "All",
|
||||||
|
"selected": true
|
||||||
|
},
|
||||||
|
"images": {
|
||||||
|
"tbm": "isch",
|
||||||
|
"href": "search?q={query}",
|
||||||
|
"name": "Images",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
"maps": {
|
||||||
|
"tbm": null,
|
||||||
|
"href": "https://maps.google.com/maps?q={query}",
|
||||||
|
"name": "Maps",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
"videos": {
|
||||||
|
"tbm": "vid",
|
||||||
|
"href": "search?q={query}",
|
||||||
|
"name": "Videos",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
"news": {
|
||||||
|
"tbm": "nws",
|
||||||
|
"href": "search?q={query}",
|
||||||
|
"name": "News",
|
||||||
|
"selected": false
|
||||||
|
},
|
||||||
|
"books": {
|
||||||
|
"tbm": "bks",
|
||||||
|
"href": "search?q={query}",
|
||||||
|
"name": "Books",
|
||||||
|
"selected": false
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,7 +35,13 @@
|
||||||
"dark": "dark",
|
"dark": "dark",
|
||||||
"system": "system",
|
"system": "system",
|
||||||
"ratelimit": "Instance has been ratelimited",
|
"ratelimit": "Instance has been ratelimited",
|
||||||
"continue-search": "Continue your search with Farside"
|
"continue-search": "Continue your search with Farside",
|
||||||
|
"all": "All",
|
||||||
|
"images": "Images",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Videos",
|
||||||
|
"news": "News",
|
||||||
|
"books": "Books"
|
||||||
},
|
},
|
||||||
"lang_nl": {
|
"lang_nl": {
|
||||||
"search": "Zoeken",
|
"search": "Zoeken",
|
||||||
|
@ -73,7 +79,13 @@
|
||||||
"dark": "donker",
|
"dark": "donker",
|
||||||
"system": "systeeminstellingen",
|
"system": "systeeminstellingen",
|
||||||
"ratelimit": "Instantie is beperkt in snelheid",
|
"ratelimit": "Instantie is beperkt in snelheid",
|
||||||
"continue-search": "Ga verder met zoeken met Farside"
|
"continue-search": "Ga verder met zoeken met Farside",
|
||||||
|
"all": "Alle",
|
||||||
|
"images": "Afbeeldingen",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Videos",
|
||||||
|
"news": "Nieuws",
|
||||||
|
"books": "Boeken"
|
||||||
},
|
},
|
||||||
"lang_de": {
|
"lang_de": {
|
||||||
"search": "Suchen",
|
"search": "Suchen",
|
||||||
|
@ -111,7 +123,13 @@
|
||||||
"dark": "dunkel",
|
"dark": "dunkel",
|
||||||
"system": "Systemeinstellung",
|
"system": "Systemeinstellung",
|
||||||
"ratelimit": "Instanz wurde ratenbegrenzt",
|
"ratelimit": "Instanz wurde ratenbegrenzt",
|
||||||
"continue-search": "Setzen Sie Ihre Suche fort mit Farside"
|
"continue-search": "Setzen Sie Ihre Suche fort mit Farside",
|
||||||
|
"all": "Alle",
|
||||||
|
"images": "Bilder",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Videos",
|
||||||
|
"news": "Nieuws",
|
||||||
|
"books": "Bücher"
|
||||||
},
|
},
|
||||||
"lang_es": {
|
"lang_es": {
|
||||||
"search": "Buscar",
|
"search": "Buscar",
|
||||||
|
@ -149,7 +167,13 @@
|
||||||
"dark": "oscuro",
|
"dark": "oscuro",
|
||||||
"system": "configuración del sistema",
|
"system": "configuración del sistema",
|
||||||
"ratelimit": "La instancia ha sido ratelimited",
|
"ratelimit": "La instancia ha sido ratelimited",
|
||||||
"continue-search": "Continúe su búsqueda con Farside"
|
"continue-search": "Continúe su búsqueda con Farside",
|
||||||
|
"all": "Todo",
|
||||||
|
"images": "Imágenes",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Vídeos",
|
||||||
|
"news": "Noticias",
|
||||||
|
"books": "Libros"
|
||||||
},
|
},
|
||||||
"lang_it": {
|
"lang_it": {
|
||||||
"search": "Cerca",
|
"search": "Cerca",
|
||||||
|
@ -187,7 +211,13 @@
|
||||||
"dark": "notte",
|
"dark": "notte",
|
||||||
"system": "impostazioni di sistema",
|
"system": "impostazioni di sistema",
|
||||||
"ratelimit": "L'istanza è stata limitata alla velocità",
|
"ratelimit": "L'istanza è stata limitata alla velocità",
|
||||||
"continue-search": "Continua la tua ricerca con Farside"
|
"continue-search": "Continua la tua ricerca con Farside",
|
||||||
|
"all": "Tutti",
|
||||||
|
"images": "Immagini",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Video",
|
||||||
|
"news": "Notizie",
|
||||||
|
"books": "Libri"
|
||||||
},
|
},
|
||||||
"lang_pt": {
|
"lang_pt": {
|
||||||
"search": "Pesquisar",
|
"search": "Pesquisar",
|
||||||
|
@ -225,7 +255,13 @@
|
||||||
"dark": "escuro",
|
"dark": "escuro",
|
||||||
"system": "configuração de sistema",
|
"system": "configuração de sistema",
|
||||||
"ratelimit": "A instância foi limitada pela taxa",
|
"ratelimit": "A instância foi limitada pela taxa",
|
||||||
"continue-search": "Continue sua pesquisa com Farside"
|
"continue-search": "Continue sua pesquisa com Farside",
|
||||||
|
"all": "Todas",
|
||||||
|
"images": "Imagens",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Vídeos",
|
||||||
|
"news": "Notícias",
|
||||||
|
"books": "Livros"
|
||||||
},
|
},
|
||||||
"lang_ru": {
|
"lang_ru": {
|
||||||
"search": "Поиск",
|
"search": "Поиск",
|
||||||
|
@ -263,7 +299,13 @@
|
||||||
"dark": "темное",
|
"dark": "темное",
|
||||||
"system": "системное",
|
"system": "системное",
|
||||||
"ratelimit": "Число экземпляров ограничено",
|
"ratelimit": "Число экземпляров ограничено",
|
||||||
"continue-search": "Продолжайте поиск с Farside"
|
"continue-search": "Продолжайте поиск с Farside",
|
||||||
|
"all": "Все",
|
||||||
|
"images": "Картинки",
|
||||||
|
"maps": "Карты",
|
||||||
|
"videos": "Видео",
|
||||||
|
"news": "Новости",
|
||||||
|
"books": "Книги"
|
||||||
},
|
},
|
||||||
"lang_zh-CN": {
|
"lang_zh-CN": {
|
||||||
"search": "搜索",
|
"search": "搜索",
|
||||||
|
@ -301,7 +343,13 @@
|
||||||
"dark": "黑暗的",
|
"dark": "黑暗的",
|
||||||
"system": "系统设置",
|
"system": "系统设置",
|
||||||
"ratelimit": "实例已被限速",
|
"ratelimit": "实例已被限速",
|
||||||
"continue-search": "继续搜索 Farside"
|
"continue-search": "继续搜索 Farside",
|
||||||
|
"all": "全部",
|
||||||
|
"images": "圖片",
|
||||||
|
"maps": "影片",
|
||||||
|
"videos": "地圖",
|
||||||
|
"news": "新聞",
|
||||||
|
"books": "書籍"
|
||||||
},
|
},
|
||||||
"lang_si": {
|
"lang_si": {
|
||||||
"search": "සොයන්න",
|
"search": "සොයන්න",
|
||||||
|
@ -339,7 +387,13 @@
|
||||||
"dark": "අඳුරු",
|
"dark": "අඳුරු",
|
||||||
"system": "පද්ධතිය",
|
"system": "පද්ධතිය",
|
||||||
"ratelimit": "සේවාදායකය අනුපාතනය කර ඇත",
|
"ratelimit": "සේවාදායකය අනුපාතනය කර ඇත",
|
||||||
"continue-search": "Farside සමඟ ඔබගේ සෙවුම කරගෙන යන්න"
|
"continue-search": "Farside සමඟ ඔබගේ සෙවුම කරගෙන යන්න",
|
||||||
|
"all": "සියල්ල",
|
||||||
|
"images": "රූප",
|
||||||
|
"maps": "සිතියම්",
|
||||||
|
"videos": "වීඩියෝ",
|
||||||
|
"news": "අනුරූප",
|
||||||
|
"books": "පොත්"
|
||||||
},
|
},
|
||||||
"lang_fr": {
|
"lang_fr": {
|
||||||
"search": "Chercher",
|
"search": "Chercher",
|
||||||
|
@ -377,7 +431,13 @@
|
||||||
"dark": "sombre",
|
"dark": "sombre",
|
||||||
"system": "système",
|
"system": "système",
|
||||||
"ratelimit": "Le débit de l'instance a été limité",
|
"ratelimit": "Le débit de l'instance a été limité",
|
||||||
"continue-search": "Continuez votre recherche avec Farside"
|
"continue-search": "Continuez votre recherche avec Farside",
|
||||||
|
"all": "Tous",
|
||||||
|
"images": "Images",
|
||||||
|
"maps": "Maps",
|
||||||
|
"videos": "Vidéos",
|
||||||
|
"news": "Actualités",
|
||||||
|
"books": "Livres"
|
||||||
},
|
},
|
||||||
"lang_fa": {
|
"lang_fa": {
|
||||||
"search": "جستجو",
|
"search": "جستجو",
|
||||||
|
@ -415,7 +475,13 @@
|
||||||
"dark": "تیره",
|
"dark": "تیره",
|
||||||
"system": "سیستم",
|
"system": "سیستم",
|
||||||
"ratelimit": "نمونه با نرخ محدود شده است",
|
"ratelimit": "نمونه با نرخ محدود شده است",
|
||||||
"continue-search": "Farside جستجوی خود را با "
|
"continue-search": "Farside جستجوی خود را با ",
|
||||||
|
"all": "همه",
|
||||||
|
"images": "تصاویر",
|
||||||
|
"maps": "نقشهها",
|
||||||
|
"videos": "ویدئوها",
|
||||||
|
"news": "اخبار",
|
||||||
|
"books": "کتابها"
|
||||||
},
|
},
|
||||||
"lang_cs": {
|
"lang_cs": {
|
||||||
"search": "Hledat",
|
"search": "Hledat",
|
||||||
|
@ -453,7 +519,13 @@
|
||||||
"dark": "Tmavý",
|
"dark": "Tmavý",
|
||||||
"system": "Systémový",
|
"system": "Systémový",
|
||||||
"ratelimit": "Instance byla omezena sazbou",
|
"ratelimit": "Instance byla omezena sazbou",
|
||||||
"continue-search": "Pokračujte ve vyhledávání pomocí Farside"
|
"continue-search": "Pokračujte ve vyhledávání pomocí Farside",
|
||||||
|
"all": "Vše",
|
||||||
|
"images": "Obrázky",
|
||||||
|
"maps": "Mapy",
|
||||||
|
"videos": "Videa",
|
||||||
|
"news": "Zprávy",
|
||||||
|
"books": "Knihy"
|
||||||
},
|
},
|
||||||
"lang_zh-TW": {
|
"lang_zh-TW": {
|
||||||
"search": "搜尋",
|
"search": "搜尋",
|
||||||
|
@ -491,7 +563,13 @@
|
||||||
"dark": "黑暗的",
|
"dark": "黑暗的",
|
||||||
"system": "依系統",
|
"system": "依系統",
|
||||||
"ratelimit": "實例已被限速",
|
"ratelimit": "實例已被限速",
|
||||||
"continue-search": "繼續搜索 Farside"
|
"continue-search": "繼續搜索 Farside",
|
||||||
|
"all": "全部",
|
||||||
|
"images": "圖片",
|
||||||
|
"maps": "影片",
|
||||||
|
"videos": "地圖",
|
||||||
|
"news": "新聞",
|
||||||
|
"books": "書籍"
|
||||||
},
|
},
|
||||||
"lang_bg": {
|
"lang_bg": {
|
||||||
"search": "Търсене",
|
"search": "Търсене",
|
||||||
|
@ -529,7 +607,13 @@
|
||||||
"dark": "тъмна",
|
"dark": "тъмна",
|
||||||
"system": "системна",
|
"system": "системна",
|
||||||
"ratelimit": "Екземплярът е с ограничена скорост",
|
"ratelimit": "Екземплярът е с ограничена скорост",
|
||||||
"continue-search": "Продължете търсенето си с Farside"
|
"continue-search": "Продължете търсенето си с Farside",
|
||||||
|
"all": "Всичкo",
|
||||||
|
"images": "Изображения",
|
||||||
|
"maps": "Видеоклипове",
|
||||||
|
"videos": "Новини",
|
||||||
|
"news": "Карти",
|
||||||
|
"books": "Книги"
|
||||||
},
|
},
|
||||||
"lang_hi": {
|
"lang_hi": {
|
||||||
"search": "खोज",
|
"search": "खोज",
|
||||||
|
@ -567,7 +651,13 @@
|
||||||
"dark": "अंधेरा",
|
"dark": "अंधेरा",
|
||||||
"system": "प्रणाली",
|
"system": "प्रणाली",
|
||||||
"ratelimit": "इंस्टेंस को सीमित कर दिया गया है",
|
"ratelimit": "इंस्टेंस को सीमित कर दिया गया है",
|
||||||
"continue-search": "के साथ अपनी खोज जारी रखें Farside"
|
"continue-search": "के साथ अपनी खोज जारी रखें Farside",
|
||||||
|
"all": "सभी",
|
||||||
|
"images": "इमेज",
|
||||||
|
"maps": "वीडियो",
|
||||||
|
"videos": "मैप",
|
||||||
|
"news": "समाचार",
|
||||||
|
"books": "किताबें"
|
||||||
},
|
},
|
||||||
"lang_ja": {
|
"lang_ja": {
|
||||||
"search": "検索",
|
"search": "検索",
|
||||||
|
@ -605,6 +695,12 @@
|
||||||
"dark": "ダーク",
|
"dark": "ダーク",
|
||||||
"system": "自動",
|
"system": "自動",
|
||||||
"ratelimit": "インスタンスはレート制限されています",
|
"ratelimit": "インスタンスはレート制限されています",
|
||||||
"continue-search": "で検索を続ける Farside"
|
"continue-search": "で検索を続ける Farside",
|
||||||
|
"all": "すべて",
|
||||||
|
"images": "画像",
|
||||||
|
"maps": "地図",
|
||||||
|
"videos": "動画",
|
||||||
|
"news": "ニュース",
|
||||||
|
"books": "書籍"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{% if mobile %}
|
{% if mobile %}
|
||||||
<header>
|
<header>
|
||||||
<div class="bz1lBb header-div">
|
<div class="header-div">
|
||||||
<form class="search-form Pg70bf"
|
<form class="search-form header"
|
||||||
id="search-form"
|
id="search-form"
|
||||||
method="{{ 'GET' if config.get_only else 'POST' }}">
|
method="{{ 'GET' if config.get_only else 'POST' }}">
|
||||||
<a class="logo-link mobile-logo" href="home">
|
<a class="logo-link mobile-logo" href="home">
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<div class="H0PQec mobile-input-div">
|
<div class="H0PQec mobile-input-div">
|
||||||
<div class="sbc esbc autocomplete">
|
<div class="autocomplete-mobile esbc autocomplete">
|
||||||
<input
|
<input
|
||||||
id="search-bar"
|
id="search-bar"
|
||||||
class="mobile-search-bar"
|
class="mobile-search-bar"
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
class="noHIxc"
|
class="search-bar-input"
|
||||||
name="q"
|
name="q"
|
||||||
type="text"
|
type="text"
|
||||||
value="{{ clean_query(query) }}"
|
value="{{ clean_query(query) }}"
|
||||||
|
@ -31,6 +31,25 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="header-tab-div">
|
||||||
|
<div class="header-tab-div-2">
|
||||||
|
<div class="header-tab-div-3">
|
||||||
|
<div class="mobile-header header-tab">
|
||||||
|
{% for tab_id, tab_content in tabs.items() %}
|
||||||
|
{% if tab_content['selected'] %}
|
||||||
|
<span class="mobile-tab-span">{{ tab_content['name'] }}</span>
|
||||||
|
{% else %}
|
||||||
|
<a class="header-tab-a" href="{{ tab_content['href'] }}">{{ tab_content['name'] }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="header-tab-div-end"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="" id="s">
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
{% else %}
|
{% else %}
|
||||||
<header>
|
<header>
|
||||||
|
@ -53,7 +72,7 @@
|
||||||
autocapitalize="none"
|
autocapitalize="none"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
class="search-bar-desktop noHIxc"
|
class="search-bar-desktop search-bar-input"
|
||||||
name="q"
|
name="q"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -67,6 +86,25 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
<div>
|
||||||
|
<div class="header-tab-div">
|
||||||
|
<div class="header-tab-div-2">
|
||||||
|
<div class="header-tab-div-3">
|
||||||
|
<div class="desktop-header header-tab">
|
||||||
|
{% for tab_id, tab_content in tabs.items() %}
|
||||||
|
{% if tab_content['selected'] %}
|
||||||
|
<span class="header-tab-span">{{ tab_content['name'] }}</span>
|
||||||
|
{% else %}
|
||||||
|
<a class="header-tab-a" href="{{ tab_content['href'] }}">{{ tab_content['name'] }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
<div class="header-tab-div-end"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="" id="s">
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<script type="text/javascript" src="{{ cb_url('header.js') }}"></script>
|
<script type="text/javascript" src="{{ cb_url('header.js') }}"></script>
|
||||||
|
|
|
@ -1,116 +1,390 @@
|
||||||
<!DOCTYPE html>
|
<div>
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta content="application/xhtml+xml; charset=utf-8" http-equiv="Content-Type"/>
|
|
||||||
<meta content="no-cache" name="Cache-Control"/>
|
|
||||||
<title>
|
|
||||||
</title>
|
|
||||||
<style>
|
<style>
|
||||||
a{text-decoration:none;color:inherit}a:hover{text-decoration:underline}a img{border:0}body{font-family:Roboto,Helvetica,Arial,sans-serif;padding:8px;margin:0 auto;max-width:700px;min-width:240px;}.FbhRzb{border-left:thin solid #dadce0;border-right:thin solid #dadce0;border-top:thin solid #dadce0;height:40px;overflow:hidden}.n692Zd{margin-bottom:10px}.cvifge{height:40px;border-spacing:0;width:100%;}.QvGUP{height:40px;padding:0 8px 0 8px;vertical-align:top}.O4cRJf{height:40px;width:100%;padding:0;padding-right:16px}.O1ePr{height:40px;padding:0;vertical-align:top}.kgJEQe{height:36px;width:98px;vertical-align:top;margin-top:4px}.lXLRf{vertical-align:top}.MhzMZd{border:0;vertical-align:middle;font-size:14px;height:40px;padding:0;width:100%;padding-left:16px}.xB0fq{height:40px;border:none;font-size:14px;background-color:#4285f4;color:#fff;padding:0 16px;margin:0;vertical-align:top;cursor:pointer}.xB0fq:focus{border:1px solid #000}.M7pB2{border:thin solid #dadce0;margin:0 0 3px 0;font-size:13px;font-weight:500;height:40px}.euZec{width:100%;height:40px;text-align:center;border-spacing:0}table.euZec td{padding:0;width:25%}.QIqI7{display:inline-block;padding-top:4px;font-weight:bold;color:#4285f4}.EY24We{border-bottom:2px solid #4285f4}.CsQyDc{display:inline-block;color:#70757a}.TuS8Ad{font-size:14px}.HddGcc{padding:8px;color:#70757a}.dzp8ae{font-weight:bold;color:#3c4043}.rEM8G{color:#70757a}.bookcf{table-layout:fixed;width:100%;border-spacing:0}.InWNIe{text-align:center}.uZgmoc{border:thin solid #dadce0;color:#70757a;font-size:14px;text-align:center;table-layout:fixed;width:100%}.frGj1b{display:block;padding:12px 0 12px 0;width:100%}.BnJWBc{text-align:center;padding:6px 0 13px 0;height:35px}.e3goi{vertical-align:top;padding:0;height:180px}.GpQGbf{margin:auto;border-collapse:collapse;border-spacing:0;width:100%}
|
html {
|
||||||
|
font-family: Roboto, Helvetica Neue, Arial, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
color: #3c4043;
|
||||||
|
word-wrap: break-word;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
padding: 0 8px;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 736px;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
a img {
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.FbhRzb {
|
||||||
|
border-left: thin solid #dadce0;
|
||||||
|
border-right: thin solid #dadce0;
|
||||||
|
border-top: thin solid #dadce0;
|
||||||
|
height: 40px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.n692Zd {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.cvifge {
|
||||||
|
height: 40px;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.QvGUP {
|
||||||
|
height: 40px;
|
||||||
|
padding: 0 8px 0 8px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.O4cRJf {
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
.O1ePr {
|
||||||
|
height: 40px;
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.kgJEQe {
|
||||||
|
height: 36px;
|
||||||
|
width: 98px;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
.lXLRf {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.MhzMZd {
|
||||||
|
border: 0;
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 40px;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 16px;
|
||||||
|
}
|
||||||
|
.xB0fq {
|
||||||
|
height: 40px;
|
||||||
|
border: none;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #4285f4;
|
||||||
|
color: #fff;
|
||||||
|
padding: 0 16px;
|
||||||
|
margin: 0;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.xB0fq:focus {
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
.M7pB2 {
|
||||||
|
border: thin solid #dadce0;
|
||||||
|
margin: 0 0 3px 0;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
.euZec {
|
||||||
|
width: 100%;
|
||||||
|
height: 40px;
|
||||||
|
text-align: center;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
table.euZec td {
|
||||||
|
padding: 0;
|
||||||
|
width: 25%;
|
||||||
|
}
|
||||||
|
.QIqI7 {
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4285f4;
|
||||||
|
}
|
||||||
|
.EY24We {
|
||||||
|
border-bottom: 2px solid #4285f4;
|
||||||
|
}
|
||||||
|
.CsQyDc {
|
||||||
|
display: inline-block;
|
||||||
|
color: #70757a;
|
||||||
|
}
|
||||||
|
.TuS8Ad {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.HddGcc {
|
||||||
|
padding: 8px;
|
||||||
|
color: #70757a;
|
||||||
|
}
|
||||||
|
.dzp8ae {
|
||||||
|
font-weight: bold;
|
||||||
|
color: #3c4043;
|
||||||
|
}
|
||||||
|
.rEM8G {
|
||||||
|
color: #70757a;
|
||||||
|
}
|
||||||
|
.bookcf {
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
.InWNIe {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.uZgmoc {
|
||||||
|
border: thin solid #dadce0;
|
||||||
|
color: #70757a;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: center;
|
||||||
|
table-layout: fixed;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.frGj1b {
|
||||||
|
display: block;
|
||||||
|
padding: 12px 0 12px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.BnJWBc {
|
||||||
|
text-align: center;
|
||||||
|
padding: 6px 0 13px 0;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
.e3goi {
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0;
|
||||||
|
height: 180px;
|
||||||
|
}
|
||||||
|
.GpQGbf {
|
||||||
|
margin: auto;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.X6ZCif {
|
||||||
|
color: #202124;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 16px;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.TwVfHd {
|
||||||
|
border-radius: 16px;
|
||||||
|
border: thin solid #dadce0;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px 8px;
|
||||||
|
margin-right: 8px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
.yekiAe {
|
||||||
|
background-color: #dadce0;
|
||||||
|
}
|
||||||
|
.svla5d {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.ezO2md {
|
||||||
|
border: thin solid #dadce0;
|
||||||
|
padding: 12px 16px 12px 16px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-family: Roboto, Helvetica, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TxbwNb {
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
.K35ahc {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.owohpf {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.RAyV4b {
|
||||||
|
width: 162px;
|
||||||
|
height: 140px;
|
||||||
|
line-height: 140px;
|
||||||
|
overflow: "hidden";
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.t0fcAb {
|
||||||
|
text-align: center;
|
||||||
|
margin: auto;
|
||||||
|
vertical-align: middle;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
.Tor4Ec {
|
||||||
|
padding-top: 2px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
.fYyStc {
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.ynsChf {
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.Fj3V3b {
|
||||||
|
color: #1967d2;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
.FrIlee {
|
||||||
|
color: #202124;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.F9iS2e {
|
||||||
|
color: #70757a;
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.WMQ2Le {
|
||||||
|
color: #70757a;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.x3G5ab {
|
||||||
|
color: #202124;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.fuLhoc {
|
||||||
|
color: #1967d2;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
.epoveb {
|
||||||
|
font-size: 32px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #202124;
|
||||||
|
}
|
||||||
|
.dXDvrc {
|
||||||
|
color: #0d652d;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.dloBPe {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.YVIcad {
|
||||||
|
color: #70757a;
|
||||||
|
}
|
||||||
|
.JkVVdd {
|
||||||
|
color: #ea4335;
|
||||||
|
}
|
||||||
|
.oXZRFd {
|
||||||
|
color: #ea4335;
|
||||||
|
}
|
||||||
|
.MQHtg {
|
||||||
|
color: #fbbc04;
|
||||||
|
}
|
||||||
|
.pyMRrb {
|
||||||
|
color: #1e8e3e;
|
||||||
|
}
|
||||||
|
.EtTZid {
|
||||||
|
color: #1e8e3e;
|
||||||
|
}
|
||||||
|
.M3vVJe {
|
||||||
|
color: #1967d2;
|
||||||
|
}
|
||||||
|
.qXLe6d {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.NHQNef {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.Cb8Z7c {
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
a.ZWRArf {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
a .CVA68e:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<style>
|
|
||||||
.X6ZCif{color:#202124;font-size:11px;line-height:16px;display:inline-block;padding-top:2px;overflow:hidden;padding-bottom:4px;width:100%}.TwVfHd{border-radius:16px;border:thin solid #dadce0;display:inline-block;padding:8px 8px;margin-right:8px;margin-bottom:4px}.yekiAe{background-color:#dadce0}.svla5d{width:100%}.ezO2md{border:thin solid #dadce0;padding:12px 16px 12px 16px;margin-bottom:10px;font-family:Roboto,Helvetica,Arial,sans-serif}.lIMUZd{font-family:Roboto,Helvetica,Arial,sans-serif}.TxbwNb{border-spacing:0}.K35ahc{width:100%}.owohpf{text-align:center}.RAyV4b{width:162px;height:140px;line-height:140px;overflow:'hidden';text-align:center;}.t0fcAb{text-align:center;margin:auto;vertical-align:middle;width:100%;height:100%;object-fit: contain}.Tor4Ec{padding-top:2px;padding-bottom:8px;}.fYyStc{word-break:break-word}.ynsChf{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.Fj3V3b{color:#1967D2;font-size:14px;line-height:20px}.FrIlee{color:#202124;font-size:11px;line-height:16px}.F9iS2e{color:#70757a;font-size:11px;line-height:16px}.WMQ2Le{color:#70757a;font-size:12px;line-height:16px}.x3G5ab{color:#202124;font-size:12px;line-height:16px}.fuLhoc{color:#1967D2;font-size:18px;line-height:24px}.epoveb{font-size:32px;line-height:40px;font-weight:400;color:#202124}.dXDvrc{color:#0d652d;font-size:14px;line-height:20px;word-wrap:break-word}.dloBPe{font-weight:bold}.YVIcad{color:#70757a}.JkVVdd{color:#ea4335}.oXZRFd{color:#ea4335}.MQHtg{color:#fbbc04}.pyMRrb{color:#1e8e3e}.EtTZid{color:#1e8e3e}.M3vVJe{color:#1967D2}.qXLe6d{display:block}.NHQNef{font-style:italic}.Cb8Z7c{white-space:pre}a.ZWRArf{text-decoration:none}a .CVA68e:hover{text-decoration:underline}
|
|
||||||
</style>
|
|
||||||
<div class="n692Zd">
|
|
||||||
<div class="BnJWBc">
|
|
||||||
<a class="lXLRf" href="/?safe=off&gbv=1&output=images&ie=UTF-8&tbm=isch&sa=X&ved=0ahUKEwjhh7TZyd_vAhWShf0HHeYzCmsQPAgC">
|
|
||||||
<img alt="Google" class="kgJEQe" src="/images/branding/searchlogo/1x/googlelogo_desk_heirloom_color_150x55dp.gif"/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="FbhRzb">
|
|
||||||
<form action="/search">
|
|
||||||
<input name="safe" type="hidden" value="off"/>
|
|
||||||
<input name="gbv" type="hidden" value="1"/>
|
|
||||||
<input name="ie" type="hidden" value="ISO-8859-1"/>
|
|
||||||
<input name="tbm" type="hidden" value="isch"/>
|
|
||||||
<input name="oq" type="hidden"/>
|
|
||||||
<input name="aqs" type="hidden"/>
|
|
||||||
<table class="cvifge">
|
|
||||||
<tr>
|
|
||||||
<td class="O4cRJf">
|
|
||||||
<!-- search input -->
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="M7pB2">
|
|
||||||
<!-- search options -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="X6ZCif"> Not present in mobile
|
|
||||||
</div> -->
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div class="lIMUZd">
|
<div class="lIMUZd">
|
||||||
<table class="By0U9">
|
<table class="By0U9">
|
||||||
<!-- correction suggested -->
|
<!-- correction suggested -->
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="GpQGbf">
|
<table class="GpQGbf">
|
||||||
{% for i in range((length // 4) + 1) %}
|
{% for i in range((length // 4) + 1) %}
|
||||||
<tr>
|
<tr>
|
||||||
{% for j in range([length - (i*4), 4]|min) %}
|
{% for j in range([length - (i*4), 4]|min) %}
|
||||||
<td align="center" class="e3goi">
|
<td align="center" class="e3goi">
|
||||||
<div class="svla5d">
|
<div class="svla5d">
|
||||||
<div>
|
<div>
|
||||||
<div class="lIMUZd">
|
<div class="lIMUZd">
|
||||||
<div>
|
<div>
|
||||||
<table class="TxbwNb">
|
<table class="TxbwNb">
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ results[(i*4)+j].web_page }}">
|
<a href="{{ results[(i*4)+j].web_page }}">
|
||||||
<div class="RAyV4b">
|
<div class="RAyV4b">
|
||||||
<img alt="" class="t0fcAb" src="{{ results[(i*4)+j].img_tbn }}"/>
|
<img
|
||||||
</div>
|
alt=""
|
||||||
</a>
|
class="t0fcAb"
|
||||||
</td>
|
src="{{ results[(i*4)+j].img_tbn }}"
|
||||||
</tr>
|
/>
|
||||||
<tr>
|
</div>
|
||||||
<td>
|
</a>
|
||||||
<a href="{{ results[(i*4)+j].web_page }}">
|
</td>
|
||||||
<div class="Tor4Ec">
|
</tr>
|
||||||
<span class="qXLe6d x3G5ab">
|
<tr>
|
||||||
<span class="fYyStc">
|
<td>
|
||||||
{{ results[(i*4)+j].domain }}
|
<a href="{{ results[(i*4)+j].web_page }}">
|
||||||
</span>
|
<div class="Tor4Ec">
|
||||||
</span>
|
<span class="qXLe6d x3G5ab">
|
||||||
</div>
|
<span class="fYyStc">
|
||||||
</a>
|
{{ results[(i*4)+j].domain }}
|
||||||
<a href="{{ results[(i*4)+j].img_url }}">
|
</span>
|
||||||
<div class="Tor4Ec">
|
</span>
|
||||||
<span class="qXLe6d F9iS2e">
|
</div>
|
||||||
<span class="fYyStc">
|
</a>
|
||||||
{{ view_label }}
|
<a href="{{ results[(i*4)+j].img_url }}">
|
||||||
</span>
|
<div class="Tor4Ec">
|
||||||
</span>
|
<span class="qXLe6d F9iS2e">
|
||||||
</div>
|
<span class="fYyStc"> {{ view_label }} </span>
|
||||||
</a>
|
</span>
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</a>
|
||||||
</table>
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<table class="uZgmoc">
|
<table class="uZgmoc">
|
||||||
<!-- next page object -->
|
<!-- next page object -->
|
||||||
</table>
|
</table>
|
||||||
<br/>
|
<br />
|
||||||
<div class="TuS8Ad">
|
</div>
|
||||||
<!-- information about user connection -->
|
|
||||||
<div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from app.models.endpoint import Endpoint
|
from app.models.endpoint import Endpoint
|
||||||
from bs4 import BeautifulSoup, NavigableString
|
from bs4 import BeautifulSoup, NavigableString
|
||||||
|
import copy
|
||||||
import html
|
import html
|
||||||
import os
|
import os
|
||||||
import urllib.parse as urlparse
|
import urllib.parse as urlparse
|
||||||
|
@ -329,3 +330,39 @@ def add_currency_card(soup: BeautifulSoup,
|
||||||
|
|
||||||
element1.insert_before(conversion_box)
|
element1.insert_before(conversion_box)
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
|
|
||||||
|
def get_tabs_content(tabs: dict,
|
||||||
|
full_query: str,
|
||||||
|
search_type: str,
|
||||||
|
translation: dict) -> dict:
|
||||||
|
"""Takes the default tabs content and updates it according to the query.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tabs: The default content for the tabs
|
||||||
|
full_query: The original search query
|
||||||
|
search_type: The current search_type
|
||||||
|
translation: The translation to get the names of the tabs
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: contains the name, the href and if the tab is selected or not
|
||||||
|
"""
|
||||||
|
tabs = copy.deepcopy(tabs)
|
||||||
|
for tab_id, tab_content in tabs.items():
|
||||||
|
# update name to desired language
|
||||||
|
if tab_id in translation:
|
||||||
|
tab_content['name'] = translation[tab_id]
|
||||||
|
|
||||||
|
# update href with query
|
||||||
|
query = full_query.replace(f'&tbm={search_type}', '')
|
||||||
|
|
||||||
|
if tab_content['tbm'] is not None:
|
||||||
|
query = f"{query}&tbm={tab_content['tbm']}"
|
||||||
|
|
||||||
|
tab_content['href'] = tab_content['href'].format(query=query)
|
||||||
|
|
||||||
|
# update if selected tab (default all tab is selected)
|
||||||
|
if tab_content['tbm'] == search_type:
|
||||||
|
tabs['all']['selected'] = False
|
||||||
|
tab_content['selected'] = True
|
||||||
|
return tabs
|
||||||
|
|
|
@ -120,6 +120,7 @@ class Search:
|
||||||
full_query = gen_query(self.query,
|
full_query = gen_query(self.query,
|
||||||
self.request_params,
|
self.request_params,
|
||||||
self.config)
|
self.config)
|
||||||
|
self.full_query = full_query
|
||||||
|
|
||||||
# force mobile search when view image is true and
|
# force mobile search when view image is true and
|
||||||
# the request is not already made by a mobile
|
# the request is not already made by a mobile
|
||||||
|
|
Loading…
Reference in New Issue