""" Convert Day One Classic/Narrate journal entries to GitJournal entries. Parse the plist XML files to extract useful metadata to be added as yaml headers for the markdown file. Handle sifttter-redux XML indentation problems by removing leading whitespaces. """ import glob import io import os import plistlib import sys import yaml def read_dayone_entry(in_file): with open(in_file, 'r') as pfile: # fix errors in sifttter-redux XML indentation data = pfile.read().replace(' <', '<') parsed = plistlib.load(io.BytesIO(data.encode('utf-8')), fmt=plistlib.FMT_XML) return parsed def write_org_entry(entry_dict, out_dir): # plistlib already parses the date, no need to use datetime creation_date = entry_dict['Creation Date'].isoformat() out_file_path = os.path.join(out_dir, f'{creation_date}.md') if os.path.exists(out_file_path): print(f'[WARNING] file {out_file_path} already exists!') return metadata = {'created': creation_date} # keeping tags and location for key in ('Tags', 'Location', 'Starred', 'Weather'): val = entry_dict.get(key) if val: metadata[key.lower()] = val metadata_yaml = yaml.dump(metadata) text = entry_dict['Entry Text'] with open(out_file_path, 'w') as out_file: out_file.write('---\n') out_file.write(metadata_yaml) out_file.write('---\n\n') out_file.write(text) print(f'[INFO ] file {out_file_path} written') def main(day_one_dir, journal_dir): if not os.path.exists(day_one_dir): print(f'[ERROR ] folder {day_one_dir} not found') sys.exit(2) if not os.path.exists(journal_dir): print(f'[INFO ] creating folder {journal_dir}') os.makedirs(journal_dir) files = glob.glob(os.path.join(day_one_dir, '*.doentry')) if not files: print(f'[WARNING] no entries found in folder {day_one_dir}') sys.exit(0) for file in files: print(f'[INFO ] reading file {file}') entry = read_dayone_entry(file) write_org_entry(entry, journal_dir) if __name__ == '__main__': args = sys.argv[1:] main(args[0], args[1])