Last active
October 18, 2024 12:10
-
-
Save DivineDominion/f7be383776bef5a57a4a812fabc4e8b7 to your computer and use it in GitHub Desktop.
Convert Day One (macOS) Journal.txt to Emacs org-mode diary/journal — https://christiantietze.de/posts/2020/10/export-day-one-journal-to-org-mode/
This file contains hidden or 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 ruby | |
# | |
# convert_dayone_to_org.rb | |
# Copyright © 2020 Christian Tietze. All rights reserved. Distributed under the MIT License. | |
# | |
# Converts a Day One plain text export (Journal.txt) into org-mode journal format. It does | |
# - Markdown image conversion from  to [[thepath.jpg]] | |
# - Extraction of images from the front of an entry; moves it right after the property drawer. | |
# - Creation of nested year/month/day date sections (see example below) | |
# | |
# TODOs: | |
# - changing the image directory name during import using an option | |
# - changing the hash-based image file names to date-time format | |
# | |
# Usage: | |
# | |
# ./convert_dayone_to_org.rb Journal.txt output.org | |
# | |
# Output: | |
# | |
# * 2020 | |
# ** 2020-03 March | |
# *** 2020-03-14 Saturday | |
# **** Here's a diary entry imported from Day One. | |
# :PROPERTIES: | |
# :CREATED: [2020-03-14 Sat 14:33] | |
# :END_PROPERTIES: | |
# **** And another one from the same day. | |
# :PROPERTIES: | |
# :CREATED: [2020-03-14 Sat 19:12] | |
# :END_PROPERTIES: | |
# ** 2020-06 June | |
# *** 2020-06-22 Monday | |
# **** Year, month, and day sections are created automatically. | |
# :PROPERTIES: | |
# :CREATED: [2020-06-22 Mon 08:06] | |
# :END_PROPERTIES: | |
require "date" | |
input, output, *rest = ARGV | |
if input.nil? | |
STDERR.puts "Usage: #{__FILE__} DAYONE_INPUT_PATH ORG_OUTPUT_PATH" | |
STDERR.puts "Missing input file path" | |
exit 1 | |
elsif output.nil? | |
STDERR.puts "Usage: #{__FILE__} DAYONE_INPUT_PATH ORG_OUTPUT_PATH" | |
STDERR.puts "Missing output file path" | |
exit 1 | |
end | |
File.open(output, "w") do |out| | |
# Cached values to make sub-headings | |
year = nil | |
month = nil | |
day = nil | |
props = {} | |
File.readlines(input).each do |line| | |
if /\A\t(?<key>\w+):\t(?<value>.*+)$/ =~ line | |
# Collect metadata in `props` dictionary | |
case key | |
when "Date" | |
date = DateTime.parse(value) | |
props["Created"] = date.strftime("[%Y-%m-%d %a %H:%M]") | |
# Convert date lines to new entries in org | |
# Output: "* 2020" | |
if year != date.year | |
out.puts "* #{date.year}" | |
year = date.year | |
month = nil | |
end | |
# Output: "** 2020-03 March" | |
if month != date.month | |
out.puts "** #{date.strftime("%Y-%m %B")}" | |
month = date.month | |
end | |
# Output: "*** 2020-03-12 Thursday" | |
this_day = date.strftime("%Y-%m-%d %A") | |
if day != this_day | |
out.puts "*** #{this_day}" | |
end | |
else | |
props[key] = value | |
end | |
elsif !props.empty? | |
# Produce entry title and metadata | |
if line.strip.empty? | |
# Skip empty line separator after metadata | |
else | |
# Add entry heading, handling leading entry images | |
cached_image = nil | |
if /\A!\[]\((?<path>.+)\)(?<rest>.*)$/ =~ line | |
cached_image = "[[./#{path}]]" | |
out.puts "**** #{rest}" | |
else | |
out.puts "**** #{line}" | |
end | |
# Append property drawer | |
out.puts ":PROPERTIES:" | |
out.puts(props.map { |key, value| ":" + key.upcase.to_s + ": " + value.to_s } | |
.join("\n")) | |
out.puts ":END_PROPERTIES:" | |
props = {} | |
if !cached_image.nil? | |
out.puts "" | |
out.puts cached_image | |
end | |
end | |
else | |
line = line.gsub(/!\[\]\((.+)\)/) { "[[./#{$1}]]" } | |
out.puts line | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment