Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Currency Conversion #536

Merged
merged 14 commits into from
Dec 7, 2021
9 changes: 8 additions & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
from app.request import Request, TorError
from app.utils.bangs import resolve_bang
from app.utils.misc import read_config_bool, get_client_ip
from app.utils.results import add_ip_card
from app.utils.results import add_ip_card, check_currency
from app.utils.results import add_currency_b
from app.utils.results import bold_search_terms
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
from app.utils.search import *
from app.utils.session import generate_user_key, valid_user_session
Expand Down Expand Up @@ -322,6 +323,12 @@ def search():
html_soup = bsoup(str(response), 'html.parser')
response = add_ip_card(html_soup, get_client_ip(request))

# Feature to display currency_card
conversion = check_currency(str(response))
if conversion:
html_soup = bsoup(str(response), 'html.parser')
response = add_currency_b(html_soup, conversion)

return render_template(
'display.html',
newest_version=newest_version,
Expand Down
6 changes: 5 additions & 1 deletion app/static/css/dark-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ path {
color: var(--whoogle-dark-text) !important;
}

.ip-text-div, .update_available {
.ip-text-div, .update_available, .cb_label, .cb {
color: var(--whoogle-dark-secondary-text) !important;
}

.cb:focus {
color: var(--whoogle-dark-contrast-text) !important;
}
27 changes: 27 additions & 0 deletions app/static/css/input.css
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,30 @@
height: 40px;
width: 50px;
}
.ZINbbc.xpd.O9g5cc.uUPGi input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}

.cb {
width: 40%;
overflow: hidden;
text-align: left;
line-height: 28px;
background: transparent;
border-radius: 6px;
border: 1px solid #5f6368;
font-size: 14px !important;
height: 36px;
padding: 0 0 0 12px;
margin: 10px 10px 10px 0;
}

.conversion_box {
margin-top: 15px;
}

.ZINbbc.xpd.O9g5cc.uUPGi input:focus-visible {
outline: 0;
}
6 changes: 5 additions & 1 deletion app/static/css/light-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ path {
border-bottom: 0px;
}

.ip-text-div, .update_available {
.ip-text-div, .update_available, .cb_label, .cb {
color: var(--whoogle-secondary-text) !important;
}

.cb:focus {
color: var(--whoogle-text) !important;
}
11 changes: 11 additions & 0 deletions app/static/js/currency.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function Convert(n1, n2, conversion_factor) {
// id's for currency input boxes
id1 = "cb" + n1;
id2 = "cb" + n2;

// getting the value of the input box that just got filled
var input_box = document.getElementById(id1).value;

// updating the other input box after conversion
document.getElementById(id2).value = ((input_box * conversion_factor).toFixed(2));
}
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions app/templates/display.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@
<script src="{{ cb_url('autocomplete.js') }}"></script>
<script src="{{ cb_url('utils.js') }}"></script>
<script src="{{ cb_url('keyboard.js') }}"></script>
<script src="{{ cb_url('currency.js') }}"></script>
</html>
87 changes: 87 additions & 0 deletions app/utils/results.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,90 @@ def add_ip_card(html_soup: BeautifulSoup, ip: str) -> BeautifulSoup:
# Inserting the element
ref_element.insert_before(ip_tag)
return html_soup


def check_currency(response: str):
"""Check whether the results have currency conversion

Args:
response: Search query Result

Returns:
list
vacom13 marked this conversation as resolved.
Show resolved Hide resolved

"""
soup = BeautifulSoup(response, 'html.parser')
a = soup.find(class_='ZINbbc xpd O9g5cc uUPGi')
tag = a.find('a')
if tag and tag['href'] == 'https://g.co/gfd':
currency1 = soup.find(class_="xUrNXd UMOHqf")
currency2 = soup.select_one('.kCrYT'
' .BNeawe.iBp4i.AP7Wnd '
'.BNeawe.iBp4i.AP7Wnd')
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
currency1 = currency1.text.rstrip('=').split(' ', 1)
currency2 = currency2.text.split(' ', 1)
return [float(currency1[0]), currency1[1],
float(currency2[0]), currency2[1]]
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
return None


def add_currency_b(soup: BeautifulSoup,
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
conversion_details: list) -> BeautifulSoup:
"""Adds the currency conversion boxes
to response of the search query

Args:
soup: Parsed search result
conversion_details: list of currency
related information

Returns:
BeautifulSoup
"""
# Element before which the code will be changed
# (This is the 'disclaimer' link)
element1 = soup.select_one('[class="nXE3Ob"]')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is fine since it's a single class, but it kinda makes me wonder if we should start maintaining an enum of classes used by Google, and then reference them using clearer names. Then it would also only require modifying one file if the class names ever change. So something like:

class GClass(Enum):
    result_class = 'ZINbbc'
    currency_disclaimer = 'nXE30b'
    # etc

and then reference in these instances using something like:

element1 = soup.select_one(f'[class="{GClass.currency_disclaimer}"]')

Don't worry about doing any of that in this PR, I can handle it later. I'm more just curious if you had any thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @benbusby. Sorry, I have been down with the flu and so didn't get time to check these out before 😅. I do think it would be a good idea to maintain an enum of classes used by google.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe after merging this pr, I could take up that issue. Since I am the one who has been using these classes a bunch!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries! Hope you're feeling better!


# Creating the conversion factor
conversion_factor = conversion_details[0]/conversion_details[2]
vacom13 marked this conversation as resolved.
Show resolved Hide resolved

# Creating a new div for the input boxes
conversion_box = soup.new_tag('div')
conversion_box['class'] = 'conversion_box'

# Currency to be converted from
input_box1 = soup.new_tag('input')
input_box1['id'] = 'cb1'
input_box1['type'] = 'number'
input_box1['class'] = 'cb Hg3mWc'
vacom13 marked this conversation as resolved.
Show resolved Hide resolved
input_box1['value'] = conversion_details[0]
input_box1['oninput'] = f'Convert(1, 2, {1/conversion_factor})'

label_box1 = soup.new_tag('label')
label_box1['for'] = 'cb1'
label_box1['class'] = 'cb_label'
label_box1.append(conversion_details[1])

br = soup.new_tag('br')

# Currency to be converted to
input_box2 = soup.new_tag('input')
input_box2['id'] = 'cb2'
input_box2['type'] = 'number'
input_box2['class'] = 'cb Hg3mWc'
input_box2['value'] = conversion_details[2]
input_box2['oninput'] = f'Convert(2, 1, {conversion_factor})'
vacom13 marked this conversation as resolved.
Show resolved Hide resolved

label_box2 = soup.new_tag('label')
label_box2['for'] = 'cb2'
label_box2['class'] = 'cb_label'
label_box2.append(conversion_details[3])

conversion_box.append(input_box1)
conversion_box.append(label_box1)
conversion_box.append(br)
conversion_box.append(input_box2)
conversion_box.append(label_box2)

element1.insert_before(conversion_box)
return soup