read-only qs section
This commit is contained in:
212
journal.py
212
journal.py
@@ -193,6 +193,17 @@ def parse_tasks_file(text):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
### HACKY HACKERY
|
||||||
|
|
||||||
|
_GLOBAL_DO_NOT_USE = {}
|
||||||
|
|
||||||
|
def init_hacky_hackery(journal):
|
||||||
|
global _GLOBAL_DO_NOT_USE
|
||||||
|
_GLOBAL_DO_NOT_USE = journal
|
||||||
|
|
||||||
|
def get_foods_file():
|
||||||
|
return parse_foods_file(_GLOBAL_DO_NOT_USE['files']['foods'])
|
||||||
|
|
||||||
### HEADER MODULES
|
### HEADER MODULES
|
||||||
|
|
||||||
def create_godword(journal, date):
|
def create_godword(journal, date):
|
||||||
@@ -403,6 +414,68 @@ def generate_default(block):
|
|||||||
def generate_info(block):
|
def generate_info(block):
|
||||||
return wrap_text(f'@info {block["value"]}')
|
return wrap_text(f'@info {block["value"]}')
|
||||||
|
|
||||||
|
### READ-ONLY STATS SECTION FUNCTIONS
|
||||||
|
|
||||||
|
def generate_stats(page):
|
||||||
|
if not page['entries']:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
result = ''
|
||||||
|
|
||||||
|
num_entries = len(page['entries'])
|
||||||
|
num_blocks = sum(len(entry['blocks']) for entry in page['entries'])
|
||||||
|
text_concat = ' '.join(b for e in page['entries'] for b in e['blocks'] if isinstance(b, str))
|
||||||
|
num_words = len(text_concat.split())
|
||||||
|
result += f'Entries: {num_entries}, Blocks: {num_blocks}, Words: {num_words}'
|
||||||
|
|
||||||
|
last_entry = max(e['timestamp'] for e in page['entries'])
|
||||||
|
first_entry = min(e['timestamp'] for e in page['entries'])
|
||||||
|
entry_delta = last_entry - first_entry
|
||||||
|
entry_hours = round(entry_delta / 60 / 60, 2)
|
||||||
|
result += f'\nFirst: {format_timestamp(first_entry)}, Last: {format_timestamp(last_entry)}, Hours: {entry_hours}'
|
||||||
|
|
||||||
|
calories = 0
|
||||||
|
carbs = 0
|
||||||
|
fat = 0
|
||||||
|
protein = 0
|
||||||
|
sugar = 0
|
||||||
|
num_meals = 0
|
||||||
|
first_meal = float('inf')
|
||||||
|
last_meal = float('-inf')
|
||||||
|
|
||||||
|
foods, recipes = get_foods_file()
|
||||||
|
for entry in page['entries']:
|
||||||
|
did_count = False
|
||||||
|
for block in entry['blocks']:
|
||||||
|
if not isinstance(block, str) and block['type'] == 'diet':
|
||||||
|
food = evaluate_food_entry(foods, recipes, block['amount'], block['food'])
|
||||||
|
|
||||||
|
if not did_count:
|
||||||
|
num_meals += 1
|
||||||
|
first_meal = min(entry['timestamp'], first_meal)
|
||||||
|
last_meal = max(entry['timestamp'], last_meal)
|
||||||
|
did_count = True
|
||||||
|
|
||||||
|
calories += food['Energy']
|
||||||
|
carbs += food.get('Carbs', 0)
|
||||||
|
fat += food.get('Fat', 0)
|
||||||
|
protein += food.get('Protein', 0)
|
||||||
|
sugar += food.get('Sugar', 0)
|
||||||
|
|
||||||
|
carbs_proportion = round(carbs * 4 / calories * 100) if carbs and calories else 0
|
||||||
|
fat_proportion = round(fat * 9 / calories * 100) if fat and calories else 0
|
||||||
|
protein_proportion = round(protein * 4 / calories * 100) if protein and calories else 0
|
||||||
|
|
||||||
|
calories, carbs, fat, protein, sugar = map(partial(round, ndigits=2), [calories, carbs, fat, protein, sugar])
|
||||||
|
|
||||||
|
meal_delta = last_meal - first_meal
|
||||||
|
meal_hours = round(meal_delta / 60 / 60, 2)
|
||||||
|
|
||||||
|
result += f'\nCalories: {calories} ({carbs_proportion}/{fat_proportion}/{protein_proportion}, {protein}/{sugar}), Meals: {num_meals}, Hours: {meal_hours}'
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
### PAGE FUNCTIONS
|
### PAGE FUNCTIONS
|
||||||
|
|
||||||
def create_header(journal, date):
|
def create_header(journal, date):
|
||||||
@@ -581,15 +654,20 @@ def generate_entry(entry):
|
|||||||
entry_modules = {
|
entry_modules = {
|
||||||
'diet': generate_diet,
|
'diet': generate_diet,
|
||||||
'exercise': generate_exercise,
|
'exercise': generate_exercise,
|
||||||
'hide': lambda _: '@hide',
|
|
||||||
'post': generate_post,
|
|
||||||
'info': generate_info,
|
|
||||||
'notes': generate_notes,
|
|
||||||
'behavior': generate_default,
|
'behavior': generate_default,
|
||||||
|
|
||||||
|
'hide': lambda _: '@hide',
|
||||||
|
'info': generate_info,
|
||||||
|
|
||||||
|
'post': generate_post,
|
||||||
|
|
||||||
|
'notes': generate_notes,
|
||||||
|
|
||||||
'task': generate_default,
|
'task': generate_default,
|
||||||
'start': generate_timer,
|
'start': generate_timer,
|
||||||
'stop': generate_timer,
|
'stop': generate_timer,
|
||||||
'done': generate_timer,
|
'done': generate_timer,
|
||||||
|
|
||||||
'notify': generate_notify,
|
'notify': generate_notify,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,6 +716,9 @@ def create_day(journal, date):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def parse_day(text):
|
def parse_day(text):
|
||||||
|
# discard read-only QS section
|
||||||
|
text = text[text.find('#'):]
|
||||||
|
|
||||||
ENTRY_RE = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ?', re.MULTILINE)
|
ENTRY_RE = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ?', re.MULTILINE)
|
||||||
|
|
||||||
header, *tmp = ENTRY_RE.split(text)
|
header, *tmp = ENTRY_RE.split(text)
|
||||||
@@ -653,7 +734,11 @@ def parse_day(text):
|
|||||||
}
|
}
|
||||||
|
|
||||||
def generate_day(page):
|
def generate_day(page):
|
||||||
result = f'# {page["title"]}'
|
result = ''
|
||||||
|
|
||||||
|
result += generate_stats(page)
|
||||||
|
|
||||||
|
result += f'\n\n# {page["title"]}'
|
||||||
|
|
||||||
result += generate_header(page['header'])
|
result += generate_header(page['header'])
|
||||||
|
|
||||||
@@ -810,7 +895,69 @@ def handle_test(args):
|
|||||||
else:
|
else:
|
||||||
print('Test passed!')
|
print('Test passed!')
|
||||||
|
|
||||||
|
|
||||||
def handle_summary(args):
|
def handle_summary(args):
|
||||||
|
def generate_food_summary(page):
|
||||||
|
result = ''
|
||||||
|
|
||||||
|
def print(str=''):
|
||||||
|
nonlocal result
|
||||||
|
result += '\n' + str
|
||||||
|
|
||||||
|
foods, recipes = get_foods_file()
|
||||||
|
|
||||||
|
daily_calories = 0.0
|
||||||
|
daily_protein = 0.0
|
||||||
|
|
||||||
|
for entry in page['entries']:
|
||||||
|
has_printed = False
|
||||||
|
entry_calories = 0.0
|
||||||
|
entry_protein = 0.0
|
||||||
|
for diet in (b for b in entry['blocks'] if type(b) != str and b['type'] == 'diet'):
|
||||||
|
if not has_printed:
|
||||||
|
print(f'-- {format_timestamp(entry["timestamp"])}')
|
||||||
|
has_printed = True
|
||||||
|
|
||||||
|
value = diet['amount']
|
||||||
|
name = diet['food']
|
||||||
|
|
||||||
|
if name in recipes:
|
||||||
|
food = recipes[name]
|
||||||
|
|
||||||
|
if value == 0.0:
|
||||||
|
value = food['TOTAL']
|
||||||
|
|
||||||
|
food = {k: v*(value/food['TOTAL']) for k,v in food.items()}
|
||||||
|
elif name in foods:
|
||||||
|
if value == 0.0:
|
||||||
|
value = 100
|
||||||
|
|
||||||
|
food = {k: v*(value/100.0) for k,v in foods[name].items()}
|
||||||
|
else:
|
||||||
|
print(f'ERROR: Invalid diet entry: {diet}')
|
||||||
|
continue
|
||||||
|
|
||||||
|
protein = round(food.get('Protein', 0.0), 2)
|
||||||
|
calories = round(food.get('Energy', 0.0), 2)
|
||||||
|
|
||||||
|
entry_calories += calories
|
||||||
|
entry_protein += protein
|
||||||
|
|
||||||
|
print(f'{name:<20} {value:<6}g, {calories:<6}kcal, {protein:<6}g protein')
|
||||||
|
|
||||||
|
if has_printed:
|
||||||
|
entry_calories = round(entry_calories, 2)
|
||||||
|
entry_protein = round(entry_protein, 2)
|
||||||
|
print(f'-- TOTAL: {entry_calories}kcal, {entry_protein}g protein')
|
||||||
|
print()
|
||||||
|
|
||||||
|
daily_calories += entry_calories
|
||||||
|
daily_protein += entry_protein
|
||||||
|
|
||||||
|
print(f'-- DAILY TOTAL ({daily_calories}kcal, {daily_protein}g protein)')
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
subcommand = nth_or_default(0, args, 'today')
|
subcommand = nth_or_default(0, args, 'today')
|
||||||
|
|
||||||
date = evaluate_time_expression(subcommand)
|
date = evaluate_time_expression(subcommand)
|
||||||
@@ -822,62 +969,13 @@ def handle_summary(args):
|
|||||||
|
|
||||||
journal = load_journal()
|
journal = load_journal()
|
||||||
|
|
||||||
foods, recipes = parse_foods_file(journal['files']['foods'])
|
print(generate_food_summary(journal['days'][date]))
|
||||||
|
|
||||||
daily_grams = 0.0
|
|
||||||
daily_calories = 0.0
|
|
||||||
daily_protein = 0.0
|
|
||||||
|
|
||||||
for entry in journal['days'][date]['entries']:
|
|
||||||
has_printed = False
|
|
||||||
entry_calories = 0.0
|
|
||||||
entry_protein = 0.0
|
|
||||||
for diet in (b for b in entry['blocks'] if type(b) != str and b['type'] == 'diet'):
|
|
||||||
if not has_printed:
|
|
||||||
print(f'-- {format_timestamp(entry["timestamp"])}')
|
|
||||||
has_printed = True
|
|
||||||
|
|
||||||
value = diet['amount']
|
|
||||||
name = diet['food']
|
|
||||||
|
|
||||||
if name in recipes:
|
|
||||||
food = recipes[name]
|
|
||||||
|
|
||||||
if value == 0.0:
|
|
||||||
value = food['TOTAL']
|
|
||||||
|
|
||||||
food = {k: v*(value/food['TOTAL']) for k,v in food.items()}
|
|
||||||
elif name in foods:
|
|
||||||
if value == 0.0:
|
|
||||||
value = 100
|
|
||||||
|
|
||||||
food = {k: v*(value/100.0) for k,v in foods[name].items()}
|
|
||||||
else:
|
|
||||||
print(f'ERROR: Invalid diet entry: {diet}')
|
|
||||||
continue
|
|
||||||
|
|
||||||
protein = round(food.get('Protein', 0.0), 2)
|
|
||||||
calories = round(food.get('Energy', 0.0), 2)
|
|
||||||
|
|
||||||
entry_calories += calories
|
|
||||||
entry_protein += protein
|
|
||||||
|
|
||||||
print(f'{name:<20} {value:<6}g, {calories:<6}kcal, {protein:<6}g protein')
|
|
||||||
|
|
||||||
if has_printed:
|
|
||||||
entry_calories = round(entry_calories, 2)
|
|
||||||
entry_protein = round(entry_protein, 2)
|
|
||||||
print(f'-- TOTAL: {entry_calories}kcal, {entry_protein}g protein')
|
|
||||||
print()
|
|
||||||
|
|
||||||
daily_calories += entry_calories
|
|
||||||
daily_protein += entry_protein
|
|
||||||
|
|
||||||
print(f'-- DAILY TOTAL ({daily_calories}kcal, {daily_protein}g protein)')
|
|
||||||
|
|
||||||
### MAIN
|
### MAIN
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
init_hacky_hackery(load_journal())
|
||||||
|
|
||||||
command = nth_or_default(1, sys.argv, 'open')
|
command = nth_or_default(1, sys.argv, 'open')
|
||||||
args = sys.argv[2:]
|
args = sys.argv[2:]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user