Created
June 15, 2025 11:41
-
-
Save jackbaty/55738c9a9209c90705346fdeaf5062cc to your computer and use it in GitHub Desktop.
Import org-journal entries to Day One
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
#!/bin/bash | |
# Org-journal to Day One import script | |
# Usage: ./import_org_to_dayone.sh <org-journal-file> | |
# | |
# Written mostly by Claude, with one tweak. Here's the prompt | |
# I would like a bash script that will use the dayone2 command line tool to import | |
# my Org-journal entries into the Day One app. I've attached a sample journal | |
# file. The script should loop through each org heading, derive the entry date | |
# from the CREATED property and call the dayone2 command with that date and the | |
# text from the org-journal entry. The org heading should be used as the Day One | |
# entry's title. | |
set -euo pipefail | |
# Check if file argument is provided | |
if [ $# -eq 0 ]; then | |
echo "Usage: $0 <org-journal-file>" | |
echo "Example: $0 2025-04.org" | |
exit 1 | |
fi | |
ORG_FILE="$1" | |
# Check if file exists | |
if [ ! -f "$ORG_FILE" ]; then | |
echo "Error: File '$ORG_FILE' not found." | |
exit 1 | |
fi | |
# Check if dayone2 command is available | |
if ! command -v dayone2 &> /dev/null; then | |
echo "Error: dayone2 command not found. Please install Day One CLI tools." | |
exit 1 | |
fi | |
# Function to convert YYYYMMDD to YYYY-MM-DD format | |
format_date() { | |
local date_str="$1" | |
echo "${date_str:0:4}-${date_str:4:2}-${date_str:6:2}" | |
} | |
# Function to process org file | |
process_org_file() { | |
local file="$1" | |
local current_title="" | |
local current_date="" | |
local current_content="" | |
local in_entry=false | |
local line_num=0 | |
while IFS= read -r line || [[ -n "$line" ]]; do | |
((line_num++)) | |
# Check if this is a heading line (starts with *) | |
if [[ "$line" =~ ^[[:space:]]*\*[[:space:]]+ ]]; then | |
# Process previous entry if we have one | |
if [ "$in_entry" = true ] && [ -n "$current_title" ] && [ -n "$current_date" ]; then | |
import_entry "$current_title" "$current_date" "$current_content" | |
fi | |
# Extract title (everything after the * and any spaces, but before any tags) | |
current_title=$(echo "$line" | sed -E 's/^[[:space:]]*\*+[[:space:]]+([^:]*).*/\1/' | sed 's/[[:space:]]*$//') | |
current_content="" | |
current_date="" | |
in_entry=false | |
# Check if this is a CREATED property line | |
elif [[ "$line" =~ ^[[:space:]]*:CREATED:[[:space:]]*([0-9]{8}) ]]; then | |
current_date="${BASH_REMATCH[1]}" | |
in_entry=true | |
# Skip other property lines and property drawer boundaries | |
elif [[ "$line" =~ ^[[:space:]]*: ]] || [[ "$line" =~ ^[[:space:]]*:END:[[:space:]]*$ ]]; then | |
continue | |
# Skip empty lines at the beginning of content | |
elif [ "$in_entry" = true ] && [ -z "$current_content" ] && [[ "$line" =~ ^[[:space:]]*$ ]]; then | |
continue | |
# Collect content lines (but skip setup and other meta lines) | |
elif [ "$in_entry" = true ] && ! [[ "$line" =~ ^[[:space:]]*# ]] && ! [[ "$line" =~ ^[[:space:]]*\+[A-Z] ]]; then | |
if [ -n "$current_content" ]; then | |
current_content="$current_content"$'\n'"$line" | |
else | |
current_content="$line" | |
fi | |
fi | |
done < "$file" | |
# Process the last entry | |
if [ "$in_entry" = true ] && [ -n "$current_title" ] && [ -n "$current_date" ]; then | |
import_entry "$current_title" "$current_date" "$current_content" | |
fi | |
} | |
# Function to import a single entry to Day One | |
import_entry() { | |
local title="$1" | |
local date_raw="$2" | |
local content="$3" | |
# Format date for Day One (YYYY-MM-DD) | |
local formatted_date=$(format_date "$date_raw") | |
# Clean up content (remove leading/trailing whitespace) | |
content=$(echo "$content" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') | |
# Skip entries with no content | |
if [ -z "$content" ]; then | |
echo "Skipping entry '$title' - no content" | |
return | |
fi | |
echo "Importing: $title ($formatted_date)" | |
# Create temporary file for the entry content | |
local temp_file=$(mktemp) | |
# Write content to temp file | |
echo "$content" > "$temp_file" | |
# Import to Day One using dayone2 command | |
# Format: dayone2 -d YYYY-MM-DD new < content_file | |
if dayone2 -j "Org Journal" -d "$formatted_date" new < "$temp_file"; then | |
echo "✓ Successfully imported: $title" | |
else | |
echo "✗ Failed to import: $title" | |
fi | |
# Clean up temp file | |
rm "$temp_file" | |
} | |
# Main execution | |
echo "Starting import from $ORG_FILE to Day One..." | |
echo "----------------------------------------" | |
process_org_file "$ORG_FILE" | |
echo "----------------------------------------" | |
echo "Import complete!" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment