Skip to content

Instantly share code, notes, and snippets.

@apiarian
Last active February 6, 2016 22:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save apiarian/0f8e0970af52bd03db54 to your computer and use it in GitHub Desktop.
Save apiarian/0f8e0970af52bd03db54 to your computer and use it in GitHub Desktop.
# export_dayone_entries.py
# Aleksandr Pasechnik
#
# This script goes through the Day One journal and exports each of the entries
# to a new markdown file in the `exportdir` directory. The `exportdir`
# directory is deleted and recreated each time the script is run, so best set
# it to something temporary (a subdirectory on the Desktop, for example).
# Photos are copied into the export directory too, with the same basename as
# the exported entries. The timestamp, location, weather, and tags are appended
# to the end of the file, if they are available. The script also sticks a '#'
# at the head of the first line, making that line into an H1 heading. Analogous
# to DayOne's "Bold first line" setting.
#
# NOTE: the `exportdir` is deleted and recreated each time the script is run.
# NOTE: this script ignores some of the data available in a full DayOne entry
# plist. Adapt to your own needs.
import os
import plistlib
import shutil
import pytz
import re
debug = True;
basedir = '~/Library/Mobile Documents/5U8NS4GX82~com~dayoneapp~dayone/Documents/Journal_dayone'
basedir = os.path.expanduser(basedir)
entriesdir = os.path.join(basedir, 'entries')
photosdir = os.path.join(basedir, 'photos')
exportdir = '~/Desktop/journal_export'
exportdir = os.path.expanduser(exportdir)
try:
shutil.rmtree(exportdir)
except:
pass
os.mkdir(exportdir)
filenames = os.listdir(entriesdir)
filenames = [filename for filename in filenames if filename.endswith('.doentry')]
entries = []
for filename in filenames:
filename = os.path.join(entriesdir, filename)
entry = plistlib.readPlist(filename)
photofilename = os.path.join(photosdir, entry['UUID']+'.jpg')
if os.path.exists(photofilename):
entry['__PHOTO_FILENAME__'] = photofilename
entries.append(entry)
utctimezone = pytz.utc
def degrees_to_dmsd(float_degrees):
float_degrees = abs(float_degrees)
degrees = int(float_degrees)
minutes_decimal = abs(float_degrees - degrees) * 60
minutes = int(minutes_decimal)
seconds_decimal = (minutes_decimal - minutes) * 60
seconds = int(seconds_decimal)
seconds_fraction = int((seconds_decimal - seconds) * 10)
return (degrees, minutes, seconds, seconds_fraction)
unique_tags = []
for entry in entries:
creationdate = entry['Creation Date']
timezone = pytz.timezone(entry['Time Zone'])
localtimestamp = utctimezone.localize(creationdate).astimezone(timezone)
yearpart = localtimestamp.strftime('%Y')
try:
os.mkdir(os.path.join(exportdir,yearpart))
except:
pass
monthpart = localtimestamp.strftime('%m - %B')
try:
os.mkdir(os.path.join(exportdir,yearpart,monthpart))
except:
pass
entry['__LOCAL_TIMESTAMP__'] = localtimestamp
filenamebase = localtimestamp.strftime('%Y-%m-%d %H-%M-%S %a');
f = open(os.path.join(exportdir, yearpart, monthpart, filenamebase+'.md'),'w')
f.write('# '); f.write(entry['Entry Text'].strip())
if '__PHOTO_FILENAME__' in entry.keys():
photofilename = filenamebase.replace(' ', '-')+'.jpg'
f.write('\n\n![](./{})'.format(photofilename))
shutil.copy(
entry['__PHOTO_FILENAME__'],
os.path.join(exportdir, yearpart, monthpart, photofilename)
)
f.write('\n\n---\n\n')
zero_padded_day = localtimestamp.strftime('%d')
unpadded_day = re.sub(r'^[0]?(.*)',r'\1',zero_padded_day)
f.write(
localtimestamp.strftime(
'**Timestamp:** %A, %B {}, %Y at %H:%M:%S {}\n\n'.format(unpadded_day,entry['Time Zone'].replace('_',' '))
)
)
if 'Location' in entry.keys():
location = entry['Location']
location_parts = []
for key in ['Place Name', 'Locality', 'Administrative Area', 'Country']:
try:
location_parts.append(location[key])
except:
pass
lat_lon = ''
try:
lat = float(location['Latitude'])
lon = float(location['Longitude'])
lat_unit = 'N' if lat >= 0 else 'S'
lon_unit = 'E' if lon >= 0 else 'W'
lat_dms = "{0[0]:02}˚{0[1]:02}'{0[2]:02}.{0[3]:02}\"".format(degrees_to_dmsd(lat))
lon_dms = "{0[0]:02}˚{0[1]:02}'{0[2]:02}.{0[3]:02}\"".format(degrees_to_dmsd(lon))
lat_lon = ' ({} {}, {} {})'.format(lat_dms, lat_unit, lon_dms, lon_unit)
except:
pass
f.write('**Location:** {}{}\n\n'.format(
', '.join(location_parts),
lat_lon,
))
processed_keys = [
'Place Name',
'Locality',
'Administrative Area',
'Country',
'Latitude',
'Longitude',
'Foursquare ID',
'Region',
'State',
'FourSquareLocation'
]
missed_keys = [key for key in location.keys() if key not in processed_keys]
if missed_keys and debug:
print('Missed Location Keys: {}'.format(missed_keys))
if 'Weather' in entry.keys():
weather = entry['Weather']
f.write('**Weather:** {}, {}˚F ({}˚C)\n\n'.format(
weather['Description'],
weather['Fahrenheit'],
weather['Celsius'],
))
processed_keys = [
'Description',
'Fahrenheit',
'Celsius',
'IconName',
'Wind Bearing',
'Service',
'Wind Speed KPH',
'Visibility KM',
'Relative Humidity',
'Pressure MB',
'Wind Chill Celsius',
'Sunset Date',
'Sunrise Date',
]
missed_keys = [key for key in weather.keys() if key not in processed_keys]
if missed_keys and debug:
print('Missed Weather Keys: {}'.format(missed_keys))
if 'Tags' in entry.keys() and entry['Tags']:
tagstring = ', '.join(entry['Tags'])
f.write('**Tags:** {}\n\n'.format(tagstring))
for tag in entry['Tags']:
if tag not in unique_tags:
unique_tags.append(tag)
f.close()
processed_keys = [
'Creation Date',
'Time Zone',
'Entry Text',
'__LOCAL_TIMESTAMP__',
'__PHOTO_FILENAME__',
'Starred',
'UUID',
'Tags',
'Weather',
'Location',
'Creator',
'Music',
'Activity',
'Step Count',
'Ignore Step Count',
]
missed_keys = [key for key in entry.keys() if key not in processed_keys]
if missed_keys and debug:
print('Missed keys: {}'.format(missed_keys))
unique_tags.sort()
print('Tags:')
for tag in unique_tags:
print('\t{}'.format(tag))
#import bpython
#bpython.embed(locals_ = locals())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment