Compare commits

...

25 Commits

Author SHA1 Message Date
olari
dcafd88b86 :*) 2021-07-12 14:03:45 +03:00
olari
3ef24d2bfe profiler 2021-07-05 22:09:53 +03:00
olari
468701b220 task interface 2021-07-05 15:21:10 +03:00
olari
22d1150801 search funciton 2021-07-05 14:48:00 +03:00
olari
1e352c7b06 update 2021-07-05 14:20:55 +03:00
olari
02df9b9b5f static typing? 2021-06-28 14:11:58 +03:00
olari
6181fa29ea fix post wrapping 2021-06-27 18:48:47 +03:00
olari
26232c60ae refactor header modules 2021-06-27 18:13:08 +03:00
olari
954e0c12af entry modules refactor 2021-06-27 15:18:48 +03:00
olari
760d072982 read-only qs section 2021-06-27 11:59:33 +03:00
olari
7e72871904 finish rewrite 2021-06-26 16:06:01 +03:00
olari
ad9ead66d0 test passing! 2021-06-21 17:30:14 +03:00
olari
58f1aad525 new parser 2021-06-21 12:58:34 +03:00
olari
96dda8ec5e update 2021-06-20 21:30:52 +03:00
olari
bf589d94b5 update generator 2021-06-19 17:13:48 +03:00
olari
d4067f5dca update 2021-06-19 11:54:25 +03:00
olari
195c430797 move data files out of repo 2021-06-19 11:50:19 +03:00
olari
f4c4407ebc fix parser 2021-06-18 03:50:32 +03:00
olari
d2a256bd77 fix bug 2021-06-17 16:08:17 +03:00
olari
bef8fec234 add notify 2021-06-16 17:37:28 +03:00
olari
d26ed919b7 add definition of recipes in terms of other recipes 2021-06-14 15:07:37 +03:00
olari
689c40b58d update 2021-06-11 20:56:33 +03:00
olari
557df1bb20 update 2021-06-01 12:53:48 +03:00
olari
6e07d120a2 update 2021-06-01 11:38:57 +03:00
olari
a10d3e1326 update 2021-05-31 12:47:57 +03:00
18 changed files with 1149 additions and 3582 deletions

3
.gitignore vendored
View File

@@ -1,3 +0,0 @@
**/*.csv
.ipynb_checkpoints/
__pycache__/

File diff suppressed because it is too large Load Diff

View File

@@ -1,171 +0,0 @@
from pathlib import Path
from datetime import datetime
from collections import Counter
from functools import reduce
import re
import string
import sys
from common import parse_foods_file
foods, recipes = parse_foods_file()
if len(sys.argv) > 1:
value, name = sys.argv[1:]
value = float(value.removesuffix('g'))
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:
breakpoint()
print(f'ERROR: Invalid diet entry: {content}')
from pprint import pprint
pprint(food)
exit(0)
entry_re = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', re.MULTILINE)
diet_re = re.compile(r'@diet (\d+g) ([a-zA-Z]+)')
total_entries = 0
total_words = 0
word_frequency = Counter()
total_csv = [['day', 'entries', 'words']]
daily_csv = [['day', 'entries', 'words', 'calories', 'carbs', 'fat', 'protein',
'sugar']]
entry_csv = [['timestamp', 'words']]
words_csv = [['word', 'count']]
diet_csv = [[
'timestamp', 'name', 'grams', 'calories', 'carbs', 'fat', 'protein',
'saturated_fat', 'sugar', 'fiber'
]]
output = open('diet', 'w')
for fpath in sorted((Path.home() / 'workspace' / 'journal').glob('*.md')):
day = fpath.stem
header, *tmp = entry_re.split(fpath.read_text())
entries = list(zip(tmp[::2], tmp[1::2]))
daily_entries = len(entries)
daily_words = 0
daily_calories = 0.0
daily_protein = 0.0
daily_carbs = 0.0
daily_fat = 0.0
daily_sugar = 0.0
output.write(f'-- {day}\n')
for (timestamp, content) in sorted(entries, key=lambda x: x[0]):
ts_str = timestamp
timestamp = int(datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S').timestamp())
content = '\n'.join(
part.replace('\n', ' ')
for part in content.split('\n\n')
)
for diet in diet_re.finditer(content):
value, name = diet.groups()
output.write(f'{ts_str} {name} {value}\n')
value = float(value.removesuffix('g'))
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:
breakpoint()
print(f'ERROR: Invalid diet entry: {content}')
continue
diet_csv.append((
timestamp,
name,
value,
round(food.get('Energy', 0.0), 2),
round(food.get('Carbs', 0.0), 2),
round(food.get('Fat', 0.0), 2),
round(food.get('Protein', 0.0), 2),
round(food.get('SaturatedFat', 0.0), 2),
round(food.get('Sugar', 0.0), 2),
round(food.get('Fiber', 0.0), 2),
))
daily_calories += food.get('Energy', 0.0)
daily_protein += food.get('Protein', 0.0)
daily_fat += food.get('Fat', 0.0)
daily_carbs += food.get('Carbs', 0.0)
daily_sugar += food.get('Sugar', 0.0)
words = ''.join(
c if c in string.ascii_letters+"'" else ' '
for c in content.lower()
).split()
word_frequency.update(words)
entry_words = len(words)
daily_words += entry_words
entry_csv.append([timestamp, entry_words])
daily_macros = daily_protein + daily_fat + daily_carbs
daily_csv.append([
day,
daily_entries,
daily_words,
round(daily_calories, 2),
round(100 * (daily_carbs / daily_macros) if daily_carbs else 0, 2),
round(100 * (daily_fat / daily_macros) if daily_fat else 0, 2),
round(100 * (daily_protein / daily_macros) if daily_protein else 0, 2),
round(daily_protein, 2),
round(daily_sugar, 2)
])
total_entries += daily_entries
total_words += daily_words
total_csv.append([day, total_entries, total_words])
words_csv += word_frequency.most_common()
def write_csv(fname, csv):
with open(fname, 'w') as fp:
fp.write('\n'.join(','.join(str(x) for x in row) for row in csv))
write_csv('total.csv', total_csv)
write_csv('daily.csv', daily_csv)
write_csv('entry.csv', entry_csv)
write_csv('words.csv', words_csv)
write_csv('diet.csv', diet_csv)

View File

@@ -1,5 +0,0 @@
#!/bin/bash
apack $1 *.md
rclone copy $1 gdrive:/journal-backup/
rclone copy $1 prodesk:/home/olari/journal-backup/
rm $1

View File

@@ -1,82 +0,0 @@
from pathlib import Path
from datetime import datetime
def parse_timestamp(timestamp):
return datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')
def parse_foods_file():
path = Path.home() / 'projects' / 'open-journal' / 'foods'
text = path.read_text()
foods, recipes = text.split('---')
def parse_macro(macro):
if macro == '...':
return ('INVALID', 0.0)
name, value = macro.split()
value = float(value.removesuffix('g').removesuffix('kcal'))
return (name, value)
foods = {
macros[0]: dict(parse_macro(macro) for macro in macros[1:])
for macros in [food.split('\n') for food in foods.strip().split('\n\n')]
}
def combine_values(fst, snd):
result = fst.copy()
for k,v in snd.items():
if k in fst:
result[k] += v
else:
result[k] = v
return result
def evaluate_ingredients(ingredients):
result = {}
total_weight = 0.0
for ingredient in ingredients:
k,v = parse_macro(ingredient)
if k == 'TOTAL':
result[k] = v
break
else:
total_weight += v
food = foods[k]
for kk,vv in food.items():
if kk not in result:
result[kk] = 0.0
result[kk] += vv * (v/100.0)
if 'TOTAL' not in result:
result['TOTAL'] = total_weight
return result
recipes = {
ingredients[0]: evaluate_ingredients(ingredients[1:])
for ingredients in [
recipe.split('\n') for recipe in recipes.strip().split('\n\n')
]
}
def get_calories_from_macros(mm):
calories = 0.0
for k,v in mm.items():
calories += v * {
'Carbs': 4,
'Fat': 9,
'Protein': 4
}.get(k, 0.0)
return calories
#for k,v in foods.items():
# print(round(v.get('Energy') - get_calories_from_macros(v)), k)
return foods, recipes

View File

@@ -1,24 +0,0 @@
from subprocess import run
import sys
outline = run(
['mutool', 'show', sys.argv[1], 'outline'],
capture_output=True
).stdout.decode('utf-8')
indent = 0
last_quote_index = 0
for line in outline.splitlines():
quote_index = line.find('"')
hash_index = line.find('#')
if quote_index > last_quote_index:
indent += 1
elif quote_index < last_quote_index:
indent -= 1
last_quote_index = quote_index
title = line[quote_index+1:line.find('"', quote_index+1)].strip()
page = int(line[hash_index+1:line.find(',', hash_index+1)])
print(f'{"#"*indent} {title} ({page})')

812
foods
View File

@@ -1,812 +0,0 @@
ProteinRakha
Energy 67kcal
Fat 0.2g
SaturatedFat 0.1g
Carbs 6g
Sugar 5.9g
Protein 10g
Salt 0.06g
Water
Energy 0kcal
KaneliKorppu
Energy 359kcal
Fat 6.6g
SaturatedFat 0.5g
Carbs 65g
Sugar 23g
Fiber 4g
Protein 8g
Salt 0.5g
Broccoli
Energy 34kcal
Fat 0.4g
Carbs 7g
Fiber 2.6g
Sugar 1.7g
Protein 2.8g
Apple
Energy 52kcal
Fat 0.2g
Carbs 14g
Fiber 2.4g
Sugar 10g
Protein 0.3g
BeanitHarkis
Energy 206kcal
Fat 10g
SaturatedFat 1g
Carbs 9g
Sugar 0.9g
Fiber 6.1g
Protein 16g
Salt 1.3g
HarkisRouheseos
Energy 335kcal
Fat 3.1g
SaturatedFat 0.3g
Carbs 26g
Sugar 3.7g
Fiber 12g
Protein 47g
Salt 1.0g
HazelnutIcecream
Energy 288kcal
Fat 18g
SaturatedFat 5.6g
Carbs 27g
Sugar 24g
Fiber 1.1g
Protein 4.0g
Salt 0.17g
CheesePizza
Energy 210kcal
Fat 5.3g
SaturatedFat 2.4g
Carbs 30.6g
Sugar 3.9g
Protein 8.9g
Salt 0.9g
ChiliBeans
Energy 85kcal
Carbs 12g
Sugar 2.5g
Fiber 5.8g
Protein 6.0g
Salt 0.65g
ProteinPowder
Energy 369kcal
Fat 5.4g
SaturatedFat 3.4g
Carbs 7.2g
Sugar 6.8g
Protein 72.0g
Salt 0.3g
KasviGrillimakkara
Energy 234kcal
Fat 15.2g
SaturatedFat 5.9g
Carbs 12.1g
Fiber 4.5g
Protein 10.0g
Salt 1.55g
Remoulade
Energy 486kcal
Fat 50.3g
SaturatedFat 4.0g
Carbs 7.0g
Sugar 5.2g
Protein 0.8g
Salt 1.04
ItaliamoGlassate
Energy 537kcal
Fat 32g
SaturatedFat 19g
Carbs 54g
Sugar 25g
Protein 7.3g
Salt 1g
LeipaJuusto
Energy 276kcal
Fat 22g
SaturatedFat 14g
Carbs 3.5g
Sugar 2.8g
Protein 16g
Pomegranate
Energy 83kcal
Carbs 19g
Fiber 4g
Sugar 14g
Protein 1.7g
RainbowNoodles
Energy 451kcal
Fat 18g
SaturatedFat 8.6g
Carbs 63g
Sugar 1.7g
Protein 11g
Salt 4.6g
Banana
Energy 89kcal
Carbs 22.84g
Sugar 12.23g
Fiber 2.6g
Fat 0.33g
Protein 1.09g
Oil
Energy 828kcal
Fat 92g
SaturatedFat 7g
MonosaturatedFat 57g
PolysaturatedFat 28g
Egg
Energy 155kcal
Carbs 1.12g
Fat 10.6g
Protein 12.6g
Milk
Energy 64kcal
Fat 3.5g
SaturatedFat 2.3g
Protein 3.2g
Salt 0.1g
SkimMilk
Energy 46kcal
Fat 1.5g
SaturatedFat 1.0g
Protein 3.4g
Salt 0.1g
BellPepper
Energy 31kcal
Protein 1g
Carbs 6g
Sugar 4.2g
Fiber 2.1g
Fat 0.3g
Flour
Energy 349kcal
Fat 1.4g
SaturatedFat 0.3g
Carbs 71.5g
Sugar 1.7g
Fiber 2.4g
Protein 11.4g
Salt 0.01g
GrahamFlour
Energy 330kcal
Fat 3.0g
SaturatedFat 0.5g
Carbs 56g
Sugar 0.8g
Fiber 13g
Protein 14g
Salt
Energy 0kcal
Salt 100g
Cheese
Energy 329kcal
Fat 24g
SaturatedFat 14g
Protein 27g
Salt 1.5g
Potato
Energy 68kcal
Fat 0.2g
Carbs 13.3g
Protein 1.6g
Fiber 0.8g
SweetPotato
Energy 86kcal
Carbs 20g
Fiber 3g
Sugar 4.2g
Protein 1.6g
Salad
Energy 10kcal
Fat 0.2g
SaturatedFat 0g
Carbs 1g
Sugar 0.5g
Protein 1.1g
SaladDressing
Energy 259kcal
Fat 22.3g
SaturatedFat 1.5g
Carbs 14g
Sugar 10.8g
Protein 0.4g
Salt 0.99g
PeasCornPepper
Energy 85kcal
Fat 0.7g
SaturatedFat 0.2g
Carbs 12g
Sugar 2.4g
Fiber 5.5g
Protein 4.9g
Salt 0.07g
Muesli
Energy 391kcal
Fat 10.9g
SaturatedFat 3.9g
Carbs 61.9g
Sugar 26.7g
Fiber 6g
Protein 8.4g
Salt 0.08g
Margarine
Energy 630kcal
Fat 70g
SaturatedFat 20g
UnsaturatedFat 35g
PickleSlices
Energy 54kcal
Sugar 12.1g
Salt 1g
Ketchup
Energy 102kcal
Carbs 23.2g
Sugar 22.8g
Protein 1.2g
Salt 1.8g
WholeGrainBread
Energy 255kcal
Fat 5g
SaturatedFat 0.5g
Carbs 41g
Sugar 4g
Fiber 7g
Protein 8g
Salt 1g
WhiteBread
Energy 253kcal
Fat 2.5g
SaturatedFat 0.3g
Carbs 45g
Sugar 1.1g
Fiber 6.1g
Protein 9.4g
Salt 1.1g
DarkBread
Energy 242kcal
Fat 1.3g
SaturatedFat 0.2g
Carbs 43.6g
Sugar 1.4g
Fiber 11.7g
Protein 8.2g
Salt 1.1g
KauraTyynyt
Energy 254kcal
Fat 4.1g
SaturatedFat 0.5g
Carbs 39g
Sugar 0.8g
Fiber 6.6g
Protein 12g
Salt 1.1g
BiscuitRings
Energy 541kcal
Fat 30.1g
SaturatedFat 14.8g
Carbs 61.8g
Sugar 23.1g
Protein 4.6g
Salt 0.48g
SobaChili
Energy 218kcal
Fat 9.3g
SaturatedFat 4.4g
Carbs 27.4g
Sugar 6g
Protein 4.9g
Salt 2.3g
CocaCola
Energy 42kcal
Carbs 10.6g
Sugar 10.6g
Pasta
Energy 348kcal
Fat 1.7g
SaturatedFat 0.4g
Carbs 67g
Sugar 2.5g
Fiber 4g
Protein 13g
TricolorePasta
Energy 351kcal
Fat 1.4g
SaturatedFat 0.3g
Carbs 72g
Sugar 3.9g
Protein 11g
SaskiaPeach
Energy 16kcal
Sugar 4g
GelatelliVeganIceCream
Energy 342kcal
Fat 21.3g
SaturatedFat 16g
Carbs 34.3g
Sugar 24.2g
Protein 2.3g
BrownRice
Energy 371kcal
Fat 2g
SaturatedFat 0.5g
Carbs 77g
Fiber 8.7g
Protein 7.1g
SojaRouha
Energy 77kcal
Carbs 6.2g
Sugar 3.15g
Protein 12.21g
Salt 1.34g
MonsterEnergy
Energy 47kcal
Sugar 11g
MousseCherry
Energy 535kcal
Fat 36.4g
SaturatedFat 21.2g
Carbs 41.4g
Sugar 31.4g
Protein 6.5g
FoodCream
Energy 161kcal
Fat 15g
SaturatedFat 10g
Carbs 4.7g
Sugar 3.7g
Honey
Energy 64kcal
Carbs 17g
Sugar 17g
Coffee
Energy 0kcal
Oatmeal
Energy 362kcal
Fat 7.5g
SaturatedFat 1.3g
Carbs 54g
Sugar 1.1g
Fiber 11g
Protein 14g
VahvlitortTallinn
Energy 505kcal
Fat 51g
Carbs 40g
Sugar 25g
Protein 6g
TaffelJuustoSnaks
Energy 550kcal
Fat 33g
SaturatedFat 6.2g
Carbs 51g
Sugar 3.6g
Protein 10g
Salt 1.8g
FakeChicken
Energy 142kcal
Fat 5g
SaturatedFat 0.5g
Carbs 11.3g
Sugar 1.57g
Protein 13.14g
Salt 0.39g
SourCream
Energy 139kcal
Fat 12g
SaturatedFat 6.7g
Carbs 4g
Sugar 4g
Protein 2.8g
Salt 0.1g
WhiteBeansTomatoSauce
Energy 105kcal
Protein 4g
Carbs 18g
Sugar 2g
CherryTomatoes
Energy 18kcal
Carbs 3.92g
Sugar 2.62g
Fiber 1.2g
Protein 0.88g
Fat 0.2g
BerryMustikaVaarika
Energy 85kcal
Carbs 13g
Sugar 7.2g
Fiber 4.7g
Protein 0.95g
VanilliIceCream
Energy 160kcal
Fat 6.3g
SaturatedFat 4.1g
Carbs 22.5g
Sugar 19.9g
Protein 3.2g
Salt 0.12g
Strawberry
Energy 33kcal
Carbs 8g
Fiber 2g
Sugar 4.9g
Protein 0.7g
Fat 0.3g
Cocoa
Energy 373kcal
Fat 2.9g
SaturatedFat 1.5g
Carbs 78.6g
Sugar 76.6g
Protein 4.8g
Salt 0.31g
Sugar
Energy 400kcal
Carbs 100g
Sugar 100g
KeishaCandy
Energy 553kcal
Fat 35g
SaturatedFat 18g
Carbs 47g
Sugar 45g
Protein 8.1g
Salt 0.13g
ProteinSpaghetti
Energy 350kcal
Fat 2.5g
SaturatedFat 0.6g
Carbs 66g
Sugar 3.7g
Fiber 7.5g
Protein 12g
PastaSauce
Energy 61kcal
Fat 1.9g
SaturatedFat 0.2g
Carbs 9.2g
Sugar 5.7g
Protein 1.3g
Salt 1.27g
Orange
Energy 50kcal
Carbs 13g
Fiber 2.2g
Sugar 8.5g
WokMix
Energy 36kcal
Carbs 5.5g
Sugar 3.9g
Fiber 2.7g
Protein 1.7g
Salt 0.04g
ProteinRahka
Energy 67kcal
Fat 0.2g
SaturatedFat 0.1g
Carbs 6.0g
Sugar 5.9g
Protein 10g
Salt 0.06g
Watermelon
Energy 30kcal
Carbs 8g
Sugar 6g
Fiber 0.4g
Protein 0.6g
Pringles
Energy 536kcal
Fat 32g
SaturatedFat 3g
Carbs 56g
Sugar 2.4g
Fiber 2.9g
Protein 4.6g
Salt 1.4g
GelatiPremium
Energy 339kcal
Fat 21.3g
SaturatedFat 13.1g
Carbs 30.7g
Sugar 28.5g
Protein 5.4g
Salt 0.08g
Hummus
Energy 278kcal
Fat 23.8g
SaturatedFat 2.7g
Carbs 7.7g
Sugar 0.2g
Protein 6.8g
Salt 0.92g
PureOrangeJuice
Energy 45kcal
Fat 0.2g
Carbs 9.4g
Sugar 9.4g
Protein 0.08g
Cucumber
Energy 15kcal
Carbs 3.6g
Sugar 1.7g
Fiber 0.5g
Protein 0.7g
Falafel
Energy 219kcal
Fat 8.5g
SaturatedFat 0.7g
Carbs 19.9g
Sugar 4.1g
Fiber 9.9g
Protein 10.7g
Salt 1.4g
SunflowerSeeds
Energy 616kcal
Fat 53.9g
SaturatedFat 4.5g
Carbs 5.1g
Sugar 3.4g
Protein 21.4g
Salt 0.05
HalloumiCheese
Energy 319kcal
Fat 25g
SaturatedFat 16g
Carbs 1.5g
Protein 22.0g
Salt 2.7g
Salmon
Energy 208kcal
Fat 13g
SaturatedFat 3.0g
Protein 20g
---
Omlette
BellPepper 50g
Cheese 25g
Egg 180g
Flour 25g
Milk 80g
Oil 20g
Salt 2g
RoastedVeggies
Oil 80g
Potato 1000g
SweetPotato 450g
OmletteWithoutMilk
Cheese 25g
Egg 180g
Flour 25g
Milk 80g
Oil 20g
FriedPotatoes
Potato 1560g
Oil 60g
BoiledWokMix
WokMix 400g
Oil 25g
FakeChickenVeggies
FakeChicken 250g
Oil 40g
PeasCornPepper 225g
OilVeggies
Oil 30g
PeasCornPepper 220g
MashedPotato
Margarine 40g
Milk 180g
Potato 1000g
TOTAL 1300g
Blov
BrownRice 600g
Ketchup 250g
Oil 50g
SojaRouha 300g
PeasCornPepper 225g
TOTAL 2460g
MilkSoup
Margarine 30g
Milk 500g
Oil 25g
Pasta 350g
Sugar 10g
TOTAL 1315g
MilkSoup2
Margarine 30g
Milk 480g
Oil 20g
Sugar 15g
Pasta 350g
TOTAL 1940g
Pancake
Egg 120g
Milk 600g
Oil 50g
Sugar 12g
Flour 300g
CreamPotatoes
Cheese 170g
FoodCream 450g
Oil 50g
Potato 1500g
CreamPotatoes2
Cheese 200g
FoodCream 450g
Potato 1020g
ProteinSpaghettiBolognese
ProteinSpaghetti 500g
PastaSauce 500g
TOTAL 1640g
OatmealPorridge
Oatmeal 150g
Margarine 14g
Honey 25g
TOTAL 700g
BakedPotatoes
Potato 1440g
Oil 40g
SeedAndOilSalad
Salad 120g
Cucumber 120g
CherryTomatoes 120g
Oil 15g
SunflowerSeeds 20g
FriedFalafel
Falafel 400g
Oil 30g
PastaSalad
TricolorePasta 500g
Salad 300g
Oil 20g
SaladDressing 65g
TOTAL 1675g
PastaSalad2
TricolorePasta 500g
Salad 270g
Oil 30g
SaladDressing 100g
TOTAL 1675g
ProteinShake
SkimMilk 400g
ProteinPowder 60g
MashedPotato2
Margarine 20g
Potato 760g
Milk 300g
VegeKotlet
Oil 45g
HarkisRouheseos 180g
Milk 240g
Egg 65g
GrahamFlour 60g
RoastedVeggies2
Broccoli 300g
Oil 70g
Potato 1000g
SweetPotato 300g
BeanitHarkisVeggies
Oil 60g
BeanitHarkis 250g
PeasCornPepper 200g
Ketchup 100g
TOTAL 760g
Pancake
SkimMilk 430g
Water 300g
Oil 30g
Flour 430g
Sugar 20g

1000
godword

File diff suppressed because it is too large Load Diff

3
habits
View File

@@ -1,3 +0,0 @@
take vitamins
weigh yourself
exercise

1065
journal.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,34 @@
from copy import deepcopy
from pathlib import Path
from shutil import copy
import json
journal_path = Path.home() / '.journal.json'
copy(str(journal_path), str(journal_path.with_suffix('.bkp')))
journal = json.loads(journal_path.read_text())
new_journal = deepcopy(journal)
for day in journal['days']:
new_entries = []
for entry in journal['days'][day]['entries']:
new_blocks = []
for block in entry['blocks']:
if not isinstance(block, str) and block['type'] == 'post':
new_blocks.append({
'type': 'post',
'timestamp': block.get('timestamp', entry['timestamp'] + 30)
})
if content := block.get('content'):
new_blocks.append(content)
else:
new_blocks.append(block)
entry['blocks'] = new_blocks
new_entries.append(entry)
new_journal['days'][day]['entries'] = new_entries
journal_path.write_text(json.dumps(new_journal))

View File

@@ -0,0 +1,34 @@
from copy import deepcopy
from pathlib import Path
from shutil import copy
import json
journal_path = Path.home() / '.journal.json'
copy(str(journal_path), str(journal_path.with_suffix('.bkp')))
journal = json.loads(journal_path.read_text())
new_journal = deepcopy(journal)
for day in journal['days']:
new_entries = []
for entry in journal['days'][day]['entries']:
new_blocks = []
for block in entry['blocks']:
if not isinstance(block, str) and block['type'] == 'hide':
if len(new_blocks) and not isinstance(new_blocks[-1], str) and \
new_blocks[-1]['type'] != 'tag':
new_blocks.append({'type': 'tag', 'value': ['hide']})
elif not isinstance(block, str) and block['type'] == 'info':
new_blocks.append({'type': 'tag', 'value': ['info']})
new_blocks.append('\n')
new_blocks.append(block['value'])
else:
new_blocks.append(block)
entry['blocks'] = new_blocks
new_entries.append(entry)
new_journal['days'][day]['entries'] = new_entries
journal_path.write_text(json.dumps(new_journal))

View File

@@ -0,0 +1,16 @@
from copy import deepcopy
from pathlib import Path
from shutil import copy
import json
journal_path = Path.home() / '.journal.json'
copy(str(journal_path), str(journal_path.with_suffix('.bkp')))
journal = json.loads(journal_path.read_text())
new_journal = deepcopy(journal)
for day in journal['days']:
new_journal['days'][day]['entries'] = journal['days'][day]['entries'][0]
journal_path.write_text(json.dumps(new_journal))

View File

@@ -1,42 +0,0 @@
from subprocess import run, Popen, DEVNULL
from datetime import datetime
from pathlib import Path
import random
import sys
current_date = datetime.now().strftime('%Y-%m-%d')
current_time = datetime.now().strftime('%H:%M:%S')
journal_path = Path.home() / 'workspace' / 'journal'
target_page = journal_path / f'{current_date}.md'
script_path = Path(__file__).parent
habits = '\n'.join([f'[-] {x}'
for x in (script_path / 'habits').read_text().strip().split('\n')])
words = (script_path / 'godword').read_text().strip().split('\n')
godword = '\n'.join(' '.join(random.choice(words)
for a in range(10)) for _ in range(2))
if not target_page.exists():
Popen(
['bash', str(script_path / 'backup-script.sh'), current_date+'.zip'],
cwd=str(journal_path), stdout=DEVNULL, stderr=DEVNULL
)
target_page.write_text(f'''\
# {target_page.stem}
Godword:
{godword}
Habits:
{habits}
''')
with open(target_page, 'a') as fp:
fp.write(f'\n{current_date} {current_time} ')
run(['nvim', str(target_page), '+'])

110
parse.py
View File

@@ -1,110 +0,0 @@
from datetime import datetime, timedelta
from pathlib import Path
from subprocess import run
from typing import Union
import sys
import re
JOURNAL_PATH = '/Users/olari/workspace/journal'
entry_re = re.compile(r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}')
def get_daily_file_paths() -> list[Path]:
return list(sorted(Path(JOURNAL_PATH).glob('*.md')))
def resolve_relative_time_expression(now: datetime, expr: str) -> datetime:
weekdays = [
'monday', 'tuesday', 'wednesday', 'thursday',
'friday', 'saturday', 'sunday'
]
if expr == 'today':
return now
elif expr == 'tomorrow':
return now + timedelta(days=1)
elif expr == 'yesterday':
return now - timedelta(days=1)
elif expr in weekdays:
return now - timedelta(days=now.weekday()) + weekdays.index(expr)
else:
return None
def parse_godword(content: str) -> list[str]:
return content.split()
def parse_habits(content: str) -> dict[str, bool]:
return {
line[4:]: line[1] == 'x'
for line in content.splitlines()
}
header_modules = {
'godword': (None, parse_godword),
'habits': (None, parse_habits),
}
def parse_header_module(content: str) -> tuple[str, Union[list, dict]]:
name, *content = content.splitlines()
name = name.removesuffix(':').lower()
content = '\n'.join(content)
_, parse = header_modules[name]
return name, parse(content)
def parse_header(header):
title, *modules = header.split('\n\n')
title = title.removeprefix('# ')
return {
'title': title,
'modules': dict(parse_header_module(module) for module in modules)
}
def parse_diet(content):
pass
def parse_content(content):
content = content.strip()
return {
'blocks': [b.replace('\n', ' ') for b in content.split('\n\n')]
}
def parse_timestamp(timestamp):
return datetime.strptime(timestamp, '%Y-%m-%d %H:%M:%S')
def parse_entry(entry):
return {
'timestamp': int(parse_timestamp(entry[:19]).timestamp()),
'content': parse_content(entry[19:]),
}
def parse_file(fpath):
header = {}
entries = []
buf = []
for i, line in enumerate(fpath.read_text().splitlines()):
if entry_re.match(line):
if not header:
header = parse_header('\n'.join([c.strip() for c in buf]))
else:
entries.append(parse_entry('\n'.join(buf)))
buf = [line]
else:
buf.append(line)
return {
'header': header,
'entries': entries,
}
def parse_journal():
result = {}
for fpath in get_daily_file_paths()[-5:]:
info = parse_file(fpath)
result[info['header']['title']] = info
return result
import json
open('journal.json', 'w').write(json.dumps(parse_journal()))

View File

@@ -1,99 +0,0 @@
import sys
from collections import defaultdict
from datetime import datetime, timedelta
import math
from common import parse_timestamp
content = open(sys.argv[1]).read().strip()
"""
* Total hours
* Hours today
* Hours this week
* Percentage completed
* Pages completed
* Estimated hours to completion
* Estimated completion date
"""
lines = content.splitlines()
i = 0
current_chapter = ''
result = defaultdict(float)
total_chapters = 0
completed_chapters = 0
today = datetime.now().replace(hour=0,minute=0,second=0,microsecond=0)
this_week = today - timedelta(days=7)
total_hours = 0.0
day_hours = 0.0
week_hours = 0.0
oldest_timestamp = datetime.now()
while i < len(lines):
line = lines[i].strip()
if line.startswith('#'):
current_chapter = line[line.find(' ')+1:]
total_chapters += 1
elif line.startswith('@start'):
start = parse_timestamp(line.removeprefix('@start '))
if start < oldest_timestamp:
oldest_timestamp = start
i += 1
line = lines[i].strip()
end = parse_timestamp(line.removeprefix('@stop '))
delta = end - start
hours = delta.seconds / 60 / 60
result[current_chapter] += hours
total_hours += hours
if start > this_week:
week_hours += hours
if start > today:
day_hours += hours
elif line.startswith('@done'):
completed_chapters += 1
i += 1
#from pprint import pprint
#pprint(dict(result), sort_dicts=False)
num_days = (datetime.now() - oldest_timestamp).days or 1
hours_per_day = total_hours / num_days
hours_per_chapter = total_hours / completed_chapters
hours_to_completion = hours_per_chapter * (total_chapters - completed_chapters)
days_to_completion = math.ceil(hours_to_completion / hours_per_day)
completion_date = datetime.now() + timedelta(days=days_to_completion)
completion_percentage = completed_chapters/total_chapters*100
print(f'Started on: {oldest_timestamp.strftime("%Y-%m-%d")}')
print(f'Progress: [{completed_chapters}/{total_chapters}] ({round(completion_percentage, 2)}%)')
print(f'Total: {round(total_hours, 2)}h')
print(f'Week: {round(week_hours, 2)}h')
print(f'Day: {round(day_hours, 2)}h')
print(f'Hours per day: {round(hours_per_day, 2)}h')
print(f'Hours to completion: {round(hours_to_completion, 2)}h')
print(f'Completion date: {completion_date.strftime("%Y-%m-%d")}')

View File

@@ -1,29 +0,0 @@
from pathlib import Path
from subprocess import run
import re
import sys
entry_re = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})', re.MULTILINE)
matches = []
for fpath in sorted((Path.home() / 'workspace' / 'journal').glob('*.md')):
header, *tmp = entry_re.split(fpath.read_text())
entries = list(zip(tmp[::2], tmp[1::2]))
for (timestamp, content) in sorted(entries, key=lambda x: x[0]):
content = '\n'.join(
part.replace('\n', ' ')
for part in content.split('\n\n')
)
if sys.argv[1].lower() in content.lower().split():
matches.append((timestamp, content))
buf = ''
for (ts, c) in matches:
c = c.replace('\n', ' ').strip()
buf += (f'[[{ts}]] {c}')[:80] + '\n'
run(['nvim', '-'], input=buf.encode('utf-8'))

View File

@@ -1,151 +0,0 @@
from pathlib import Path
from datetime import datetime
from collections import Counter
from functools import reduce
import re
import string
import sys
def parse_foods_file():
path = Path.home() / 'projects' / 'open-journal' / 'foods'
text = path.read_text()
foods, recipes = text.split('---')
def parse_macro(macro):
if macro == '...':
return ('INVALID', 0.0)
name, value = macro.split()
value = float(value.removesuffix('g').removesuffix('kcal'))
return (name, value)
foods = {
macros[0]: dict(parse_macro(macro) for macro in macros[1:])
for macros in [food.split('\n') for food in foods.strip().split('\n\n')]
}
def combine_values(fst, snd):
result = fst.copy()
for k,v in snd.items():
if k in fst:
result[k] += v
else:
result[k] = v
return result
def evaluate_ingredients(ingredients):
result = {}
total_weight = 0.0
for ingredient in ingredients:
k,v = parse_macro(ingredient)
if k == 'TOTAL':
result[k] = v
break
else:
total_weight += v
food = foods[k]
for kk,vv in food.items():
if kk not in result:
result[kk] = 0.0
result[kk] += vv * (v/100.0)
if 'TOTAL' not in result:
result['TOTAL'] = total_weight
return result
recipes = {
ingredients[0]: evaluate_ingredients(ingredients[1:])
for ingredients in [
recipe.split('\n') for recipe in recipes.strip().split('\n\n')
]
}
def get_calories_from_macros(mm):
calories = 0.0
for k,v in mm.items():
calories += v * {
'Carbs': 4,
'Fat': 9,
'Protein': 4
}.get(k, 0.0)
return calories
#for k,v in foods.items():
# print(round(v.get('Energy') - get_calories_from_macros(v)), k)
return foods, recipes
foods, recipes = parse_foods_file()
entry_re = re.compile(r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) ', re.MULTILINE)
diet_re = re.compile(r'@diet (\d+g) ([a-zA-Z]+)')
current_day = list(sorted((Path.home() / 'workspace' /
'journal').glob('*.md')))[-1]
header, *tmp = entry_re.split(current_day.read_text())
entries = list(zip(tmp[::2], tmp[1::2]))
daily_grams = 0.0
daily_calories = 0.0
daily_protein = 0.0
for (timestamp, content) in sorted(entries, key=lambda x: x[0]):
content = '\n'.join(
part.replace('\n', ' ')
for part in content.split('\n\n')
)
has_printed = False
entry_calories = 0.0
entry_protein = 0.0
for diet in diet_re.finditer(content):
if not has_printed:
print(f'-- {timestamp}')
has_printed = True
value, name = diet.groups()
value = float(value.removesuffix('g'))
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:
breakpoint()
print(f'ERROR: Invalid diet entry: {content}')
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)')