Skip to content

Commit 4d9f398

Browse files
authored
Merge pull request CloudBotIRC#171 from edillingham/gonzobot
added myfitnesspal plugin
2 parents 2c22c37 + ad12c17 commit 4d9f398

1 file changed

Lines changed: 90 additions & 0 deletions

File tree

plugins/myfitnesspal.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import locale
2+
import math
3+
import requests
4+
from bs4 import BeautifulSoup
5+
6+
from cloudbot import hook
7+
8+
scrape_url = "http://www.myfitnesspal.com/food/diary/{}"
9+
10+
11+
@hook.command('mfp', 'myfitnesspal')
12+
def mfp(text, bot):
13+
"""<user> - returns macros from the MyFitnessPal food diary of <user>"""
14+
request = requests.get(scrape_url.format(text))
15+
16+
if request.status_code != requests.codes.ok:
17+
return "Failed to fetch info ({})".format(request.status_code)
18+
19+
output = "Diary for {}: ".format(text)
20+
21+
try:
22+
soup = BeautifulSoup(request.text, 'html.parser')
23+
24+
title = soup.find('h1', {'class': 'main-title'})
25+
if title:
26+
if title.text == 'This Food Diary is Private':
27+
return "{}'s food diary is private.".format(text)
28+
if title.text == 'This Username is Invalid':
29+
return "User {} does not exist.".format(text)
30+
31+
# the output of table depends on the user's MFP profile configuration
32+
headers = get_headers(soup)
33+
totals = get_values(soup, 'total')
34+
remaining = get_values(soup, 'alt')
35+
36+
for idx, val in enumerate(headers['captions']):
37+
kwargs = {
38+
'caption': val,
39+
'total': totals[idx],
40+
'remain': remaining[idx],
41+
'units': headers['units'][idx],
42+
'pct': math.floor((totals[idx]/remaining[idx])*100)
43+
}
44+
45+
output += ("{caption}: {total}/{remain}{units} ({pct}%) "
46+
.format(**kwargs))
47+
48+
output += " ({})".format(scrape_url.format(text))
49+
50+
except Exception as e:
51+
print(e)
52+
output = "Error parsing results."
53+
54+
return output
55+
56+
57+
def get_headers(soup):
58+
"""get nutrient headers from the soup"""
59+
headers = {'captions': [], 'units': []}
60+
61+
footer = soup.find('tfoot')
62+
for cell in footer.findAll('td', {'class': 'nutrient-column'}):
63+
div = cell.find('div')
64+
headers['units'].append(div.text)
65+
headers['captions'].append(div.previous_sibling.strip())
66+
67+
return headers
68+
69+
70+
def get_values(soup, row_class):
71+
"""get values from a specific summary row based on the row class"""
72+
locale.setlocale(locale.LC_ALL, 'english_USA') # for number parsing
73+
74+
values = []
75+
76+
cells = soup.find('tr', {'class': row_class}).find_all('td')
77+
78+
for elem in cells[1:]:
79+
# if there's a child span with class "macro-value", use its value
80+
# otherwise use the cell text
81+
span = elem.find('span', {'class': 'macro-value'})
82+
if span:
83+
value = span.text
84+
else:
85+
value = elem.text
86+
87+
if value.strip() != '':
88+
values.append(locale.atoi(value))
89+
90+
return values

0 commit comments

Comments
 (0)