Compare commits
25 Commits
3aef7c4133
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcafd88b86 | ||
|
|
3ef24d2bfe | ||
|
|
468701b220 | ||
|
|
22d1150801 | ||
|
|
1e352c7b06 | ||
|
|
02df9b9b5f | ||
|
|
6181fa29ea | ||
|
|
26232c60ae | ||
|
|
954e0c12af | ||
|
|
760d072982 | ||
|
|
7e72871904 | ||
|
|
ad9ead66d0 | ||
|
|
58f1aad525 | ||
|
|
96dda8ec5e | ||
|
|
bf589d94b5 | ||
|
|
d4067f5dca | ||
|
|
195c430797 | ||
|
|
f4c4407ebc | ||
|
|
d2a256bd77 | ||
|
|
bef8fec234 | ||
|
|
d26ed919b7 | ||
|
|
689c40b58d | ||
|
|
557df1bb20 | ||
|
|
6e07d120a2 | ||
|
|
a10d3e1326 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
**/*.csv
|
|
||||||
.ipynb_checkpoints/
|
|
||||||
__pycache__/
|
|
||||||
1051
Untitled.ipynb
1051
Untitled.ipynb
File diff suppressed because it is too large
Load Diff
171
analyze.py
171
analyze.py
@@ -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)
|
|
||||||
@@ -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
|
|
||||||
82
common.py
82
common.py
@@ -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
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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
812
foods
@@ -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
|
|
||||||
1065
journal.py
Normal file
1065
journal.py
Normal file
File diff suppressed because it is too large
Load Diff
34
migrations/2021-06-27_post.py
Normal file
34
migrations/2021-06-27_post.py
Normal 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))
|
||||||
34
migrations/2021-06-29_tag.py
Normal file
34
migrations/2021-06-29_tag.py
Normal 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))
|
||||||
16
migrations/2021-07-06_fix.py
Normal file
16
migrations/2021-07-06_fix.py
Normal 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))
|
||||||
@@ -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
110
parse.py
@@ -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()))
|
|
||||||
99
progress.py
99
progress.py
@@ -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")}')
|
|
||||||
|
|
||||||
29
search.py
29
search.py
@@ -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'))
|
|
||||||
151
summary.py
151
summary.py
@@ -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)')
|
|
||||||
Reference in New Issue
Block a user