Skip to content

Instantly share code, notes, and snippets.

@eliduke
Last active April 24, 2026 17:57
Show Gist options
  • Select an option

  • Save eliduke/94dad4a86e6e64e50d5fa3b214b726d9 to your computer and use it in GitHub Desktop.

Select an option

Save eliduke/94dad4a86e6e64e50d5fa3b214b726d9 to your computer and use it in GitHub Desktop.
Day One JSON to Markdown Converter Script
require 'json'
require 'date'
require 'fileutils'
require 'timezone'
# Load specific Day One json data file
json_data = JSON.load_file('Media.json')
# Existing directory where to put everything
export_dir = 'Media'
# Loop through all entries
json_data['entries'].each_with_index do |post, index|
# Create directory for this post where all files will go
post_dir = FileUtils.mkdir "#{export_dir}/#{index.to_s.rjust(3, "0")}-#{post['uuid']}"
# Create internal media directory for all photos and videos related to this post
media_dir = FileUtils.mkdir "#{post_dir.first}/media"
# Create json file of the raw 'entry' for posterity / backup / cya
File.open("#{post_dir.first}/post.json", "wb") do |file|
file.write(JSON.pretty_generate(post))
end
# Loop through all photos for this post, copy and then rename with added file order
if post['photos']
post['photos'].each do |photo|
file_name = "#{photo['md5']}.#{photo['type']}"
file_order = photo['orderInEntry'].to_s.rjust(2, "0")
FileUtils.copy_file "photos/#{file_name}", "#{media_dir.first}/#{file_order}-#{file_name}"
end
end
# Loop through all videos for this post, copy and then rename with added file order
if post['videos']
post['videos'].each do |video|
file_name = "#{video['md5']}.#{video['type']}"
file_order = video['orderInEntry'].to_s.rjust(2, "0")
FileUtils.copy_file "videos/#{file_name}", "#{media_dir.first}/#{file_order}-#{file_name}"
end
end
# Set title, body, and timezone
title, body = JSON.parse(post['richText'])['contents'][0,2]
timezone = Timezone[post['timeZone']]
# Set location info
if post['location']
location = "#{post['location']['placeName']}, #{post['location']['localityName']}, #{post['location']['administrativeArea']}"
end
# Set weather and moon info
if post['weather']
temp_in_f = ((post['weather']['temperatureCelsius'] * 1.8) + 32).round
conditions = post['weather']['conditionsDescription']
moon_phase = post['weather']['moonPhaseCode'].split("-").map(&:capitalize).join(" ")
weather_and_moon = "#{temp_in_f}°F #{conditions} with a #{moon_phase} Moon"
end
# Set list of markdown image/video tags for all media in this post
media_files = Dir["#{media_dir.first}/*"]
media_list = ""
media_files.each do |media|
media_list += "![](.#{media.split(post['uuid']).last})\n\n"
end
# Create markdown file
File.open("#{post_dir.first}/post.md", "wb") do |file|
file.write(<<~EOS
# #{title['text']}
#{body['text']}
#{timezone.time_with_offset(DateTime.parse(post['creationDate']))}
#{location}
#{weather_and_moon}
#{media_list}
EOS
)
end
end
@eliduke
Copy link
Copy Markdown
Author

eliduke commented Apr 24, 2026

This is a pretty rough and tumble version that I whipped up in a couple hours, but it works pretty good!

The folder/file structure that it generates looks like this...

Screenshot 2026-04-24 at 10 57 06 AM

And each post's markdown file looks like this...

Screenshot 2026-04-24 at 10 57 25 AM

Suuuuper simple, but much better than the default markdown export.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment