Created
May 10, 2018 17:59
-
-
Save seanlane/549bb151c6df45722efa5494e934a1c8 to your computer and use it in GitHub Desktop.
Python script I use for Personal and Work journaling
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse, datetime, os, re, sys, tempfile, time | |
from subprocess import call | |
EDITOR = os.environ.get('EDITOR') if os.environ.get('EDITOR') else 'vim' | |
def create_header(): | |
""" | |
Create the template for a new personal journal entry | |
returns list of strings (lines) to be joined | |
""" | |
content = [ | |
'---', | |
'date: {}'.format(time.strftime('%Y-%m-%d', cur_date)), | |
'time: {}'.format(time.strftime('%H:%M:%S%z', cur_date)) | |
] | |
try: | |
import requests | |
resp = requests.get(url='http://ip-api.com/json') # Find location based on Public IP address | |
data = resp.json() | |
content.append('location: {}, {}, {}'.format(data['city'], data['regionName'], data['country'])) | |
except Exception as e: | |
print('Exception occurred: {}'.format(e)) | |
print("Couldn't get location, skipping. Should probably figure this out sometime.") | |
content.append('---') | |
return content | |
def work_template(base_path): | |
""" | |
Create the template for a new work journal entry | |
Most of this work is to simply copy the To Do list from the last entry and | |
paste it into this new entry, and add other sections around it. | |
base_path: Parent directory of entries | |
""" | |
content = create_header() | |
content.extend([ | |
'', | |
'# Done', | |
'', '', '' | |
]) | |
try: | |
files = {x[0]: {'dirs': x[1], 'files': x[2]} for x in os.walk(base_path)} | |
latest_year = sorted(files[base_path]['dirs'])[-1] | |
latest_month = sorted(files[os.path.join(base_path, latest_year)]['dirs'])[-1] | |
latest_date = sorted([x for x in | |
files[os.path.join(base_path, os.path.join(latest_year, latest_month))]['files'] | |
if '.md' in x])[-1] | |
last_entry_path = os.path.join(base_path, | |
os.path.join(latest_year, | |
os.path.join(latest_month, latest_date))) | |
with open(last_entry_path, 'r') as f: | |
start_todo_section = re.compile(r"^[ \t]*\#+[ \t]*To[ \t]*Do[ \t]*$") | |
next_section = re.compile(r"^[ \t]*\#+.*$") | |
todo_section = False | |
content.append('# To Do') | |
for line in f: | |
if start_todo_section.search(line): | |
todo_section = True | |
elif todo_section and next_section.search(line): | |
break | |
elif todo_section: | |
if line.strip(): | |
content.append(line.rstrip()) | |
except Exception as e: | |
print('Exception occurred: {}'.format(e)) | |
print("Couldn't get previous To Do section, continuing") | |
content.extend(['', '# Other', '', '', '']) | |
return '\n'.join(content) | |
def personal_template(): | |
""" | |
Create the template for a new work journal entry | |
base_path: Parent directory of entries | |
""" | |
content = '\n'.join(create_header()) | |
with open(os.path.join(os.path.dirname(sys.argv[0]), 'template.md')) as f: | |
content = content + '\n' + ''.join(f.readlines()) | |
return content | |
def edit_content(content_in): | |
initial_message = str.encode(content_in) # if you want to set up the file somehow | |
with tempfile.NamedTemporaryFile(suffix=".tmp") as tf: | |
tf.write(initial_message) | |
tf.flush() | |
call([EDITOR, '+set backupcopy=yes', tf.name]) | |
# do the parsing with `tf` using regular File operations. | |
# for instance: | |
tf.seek(0) | |
edited_message = tf.read().decode("utf-8") | |
return edited_message | |
parser = argparse.ArgumentParser(description="Sean's jrnl script") | |
parser.add_argument('--work', action='store_true', help="Process work entry") | |
parser.add_argument('path', help="Root directory of entries") | |
args = parser.parse_args() | |
cur_date = time.localtime() | |
base_dir = os.path.expanduser(args.path) | |
dir_path = os.path.join(base_dir, os.path.join(str(cur_date.tm_year), time.strftime('%m-%B', cur_date))) | |
file_path = os.path.join(dir_path, time.strftime('%Y-%m-%d.md', cur_date)) | |
# If there already exists an entry for today, load the contents and edit it | |
if os.path.exists(file_path): | |
with open(file_path) as f: | |
source = f.read() | |
## Allow user to edit template | |
updated_content = edit_content(source) | |
## Check if anything changed, if not don't bother saving | |
if source == updated_content: | |
sys.exit(0) | |
with open(file_path, 'w') as f: | |
f.write(updated_content) | |
sys.exit(0) | |
# If it's before 4AM local time and there is an entry for the previous day, edit that one | |
if cur_date.tm_hour < 4: | |
# Get date for yesterday | |
yes_date = (datetime.datetime.fromtimestamp(time.mktime(cur_date)).date() - datetime.timedelta(days=1)).timetuple() | |
temp_dir_path = os.path.join(base_dir, os.path.join(str(cur_date.tm_year), time.strftime('%m-%B', cur_date))) | |
temp_file_path = os.path.join(temp_dir_path, time.strftime('%Y-%m-%d.md', cur_date)) | |
if os.path.exists(temp_file_path): | |
with open(temp_file_path) as f: | |
source = f.read() | |
## Allow user to edit template | |
updated_content = edit_content(source) | |
## Check if anything changed, if not don't bother saving | |
if source == updated_content: | |
sys.exit(0) | |
with open(temp_file_path, 'w') as f: | |
f.write(updated_content) | |
sys.exit(0) | |
# Otherwise, make a new entry as required | |
## First generate source template | |
if args.work: | |
source = ''.join(work_template(base_dir)) | |
else: | |
source = ''.join(personal_template()) | |
## Allow user to edit template | |
updated_content = edit_content(source) | |
## Check if anything changed, if not don't bother saving | |
if source == updated_content: | |
sys.exit(0) | |
if not os.path.exists(dir_path): | |
os.makedirs(dir_path, mode=0o755, exist_ok=True) | |
with open(file_path, 'w') as f: | |
f.write(updated_content) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment