Skip to content

Commit

Permalink
Merge pull request coddingtonbear#161 from coddingtonbear/151_get_mea…
Browse files Browse the repository at this point in the history
…surements_problem

Fix get_measurements
  • Loading branch information
coddingtonbear committed Jun 16, 2023
2 parents 9baf832 + a66cbe5 commit 596970d
Show file tree
Hide file tree
Showing 3 changed files with 4,218 additions and 975 deletions.
67 changes: 32 additions & 35 deletions myfitnesspal/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,13 @@ def _get_url_for_date(
+ f"?date={date_str}"
)

def _get_url_for_measurements(self, page: int = 1, measurement_id: int = 1) -> str:
def _get_url_for_measurements(
self, page: int = 1, measurement_name: str = ""
) -> str:
return (
parse.urljoin(self.BASE_URL_SECURE, "measurements/edit")
+ f"?page={page}&type={measurement_id}"
+ "?"
+ parse.urlencode({"page": page, "type": measurement_name})
)

def _get_request_for_url(
Expand Down Expand Up @@ -560,10 +563,7 @@ def get_measurements(
# gather the IDs for all measurement types
measurement_ids = self._get_measurement_ids(document)

# select the measurement ID based on the input
if measurement in measurement_ids.keys():
measurement_id = measurement_ids[measurement]
else:
if measurement not in measurement_ids.keys():
raise ValueError(f"Measurement '{measurement}' does not exist.")

page = 1
Expand All @@ -573,7 +573,7 @@ def get_measurements(
while True:
# retrieve the HTML from MyFitnessPal
document = self._get_document_for_url(
self._get_url_for_measurements(page, measurement_id)
self._get_url_for_measurements(page, measurement)
)

# parse the HTML for measurement entries and add to dictionary
Expand Down Expand Up @@ -661,42 +661,39 @@ def set_measurements(
)

def _get_measurements(self, document):
# find the tr element for each measurement entry on the page
trs = document.xpath("//table[contains(@class,'check-in')]/tbody/tr")

measurements = OrderedDict()

# create a dictionary out of the date and value of each entry
for entry in trs:
measurements = []

# ensure there are measurement entries on the page
if len(entry) == 1:
return measurements
else:
measurements[entry[1].text] = entry[2].text
for next_data in document.xpath("//script[@id='__NEXT_DATA__']"):
next_data_json = json.loads(next_data.text)
for q in next_data_json["props"]["pageProps"]["dehydratedState"]["queries"]:
if "measurements" in q["queryKey"]:
if "items" in q["state"]["data"]:
measurements += q["state"]["data"]["items"]

temp_measurements = OrderedDict()
measurements_dict = OrderedDict()

# converts the date to a datetime object and the value to a float
for date in measurements:
temp_measurements[
datetime.datetime.strptime(date, "%m/%d/%Y").date()
] = self._get_numeric(measurements[date])

measurements = temp_measurements
for entry in measurements:
date = datetime.datetime.strptime(entry["date"], "%Y-%m-%d").date()
if "unit" in entry:
value = f"{entry['value']} {entry['unit']}"
else:
value = f"{entry['value']}"
measurements_dict[date] = self._get_numeric(value)

return measurements
return measurements_dict

def _get_measurement_ids(self, document) -> Dict[str, int]:

# find the option element for all of the measurement choices
options = document.xpath("//select[@id='type']/option")

ids = {}

# create a dictionary out of the text and value of each choice
for option in options:
ids[option.text] = int(option.attrib.get("value"))
for next_data in document.xpath("//script[@id='__NEXT_DATA__']"):
next_data_json = json.loads(next_data.text)
for q in next_data_json["props"]["pageProps"]["dehydratedState"]["queries"]:
if "measurementTypes" in q["queryKey"]:
for m in q["state"]["data"]:
ids[m["description"]] = m["id"]
if "measurements" in q["queryKey"]:
if q["queryKey"][1] not in ids:
ids[q["queryKey"][1]] = ""

return ids

Expand Down
Loading

0 comments on commit 596970d

Please sign in to comment.