Back up Google Calendar on Mac OS X

I wanted to ensure that I had a local backup of google calendar on my own computer. This is how I've done it. Of course, with anything like this, if you try and do the same, then you will be taking responsibility for your own foulups! First, I opened terminal and changed to my script directory

[sourcecode language="bash" light="true"] cd ~/Documents/scripts [/sourcecode]

Where you store your scripts is up to you, if you don't have a script directory, make one first by typing:

[sourcecode language="bash" light="true"] mkdir ~/Documents/scripts [/sourcecode]

Then, I made a script and made it executable. I use vi for editing, if you are not happy with vi, then open it in your text processor of choice (with vi, hit i to start editing, then escape w q return to save and quit, escape q ! return to quit only)

[sourcecode language="bash"] touch calbackup chmod 755 calbackup vi calbackup [/sourcecode]

Here is my script. You will need to go to google calendar, go to the settings of each calendar you want to back up and then copy and paste the private ical URL.

Any line with # at the start (except the first) can be deleted. Honestly, you can probably delete the first, but it's not hurting, best to keep it.

[sourcecode language="bash"] #!/bin/bash

# change this to where you wish to store your calendar backup cd ~/Documents/Dropbox/Private/Calendars

# these are variables which will be used day=$(date +%d) month=$(date +%m)

# this will be used to create directories of the form month-07 month="month-${month}"

# if we don't have a subdirectory for that month, make it if [ ! -d "$month" ]; then mkdir $month fi

# get the calendars. Repeat these as needed. # Change the URL to those the private ical URL of your calendars # Obtain this by going to google calendar and using 'settings' # on each calendar in turn

# Also, change the local name of the calendar # '-master.ics' , '-birthday.ics' etc. each time curl -silent -k (PrivateUrltoCalendar) > "${day}-master.ics" curl -silent -k (PrivateUrltoCalendar2) > "${day}-birthday.ics"

# I have about 10 entries in the above section, you will have # as many entries as you have calendars. # To avoid spamming the google server # (like a fly splatting a locomotive) # you may want to introduce a pause # between each 'curl' with something like 'sleep 1m'

# So far, we have a backup every time we run the script, # each day produces a new backup

# Now, I will have daily backups for the last month, # let's make a monthly backup

# I always want the most up to date to be the monthly backup, # but I only want backup per month.

# I don't want to redownload again, it may be easier, # but it is so slower, and would require two edits # if the calendar URL changes.

# Let's rename what we have.

for file in ${day}*.ics do newloc=$(echo $file | sed 's/[0-9]*-//g') newloc=$(echo $month/$newloc) cp $file $newloc done [/sourcecode]

If you prefer to have code without comments, here's a version and I've included the change discussed in the comments below (don't forget to also make the changes detailed above):

[sourcecode language="bash"] #!/bin/bash

cd ~/Documents/Dropbox/Private/Calendars

day=$(date +%d) month=$(date +%m) month="month-${month}"

if [ ! -d "$month" ]; then mkdir $month fi

curl -silent -k (PrivateUrltoCalendar) | awk '/BEGIN:VCALENDAR/,0' > "${day}-master.ics" curl -silent -k (PrivateUrltoCalendar2) | awk '/BEGIN:VCALENDAR/,0' > "${day}-birthday.ics"

for file in ${day}*.ics do newloc=$(echo $file | sed 's/[0-9]*-//g') newloc=$(echo $month/$newloc) cp $file $newloc done [/sourcecode]

Assuming you've made the appropriate changes, you can run your script by typing ./calbackup (or just calbackup if you have set the path to your script directory).

There will be a pause, and after about 10 seconds (for me, you may take longer), the command prompt reappears. Navigating to the directory where I have backups shows my daily backups of the form 29-master.ics, 29-birthday.ics etc - and there is a subdirectory with master.ics, birthday.ics etc.

When the month ticks over, that subdirectory will no longer be updated, and a new one will start to be maintained. Thus, if we run the script daily, we will have a monthly backup (lasting 12 months) and daily backups for the last month.

I do not wish, however, to have to remember to run the script.

So now I want to automate the process. If you don't like vi, use your editor of choice.

[sourcecode language="bash"] cd ~/Library/LaunchAgents touch com.google.calendar.mine.plist chmod 644 com.google.calendar.mine.plist vi com.google.calendar.mine.plist [/sourcecode]

Within com.google.calendar.plist, I need to tell the computer where the script is, and also how often I want it to run. You will need to ensure that the path is correct for your script, e.g. mine is in ~/Documents/scripts, so my path is /Users/myusername/Documents/scripts/calbackup

I want it to run every 6 hours (more than needed, but I'd rather that than too few, also I don't want it running all the time). I might even increase this time to eight or 12 hours. I don't think I'd go for 24, as if there is a network issue when the script runs, no backup is made that day. Six hours in seconds is 6x60x60 or 21600.

[sourcecode langage="xml"] <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.google.calendar</string> <key>ProgramArguments</key> <array> <string>/bin/sh</string> <string>/path/to/your/scripts/calbackup</string> </array> <key>RunAtLoad</key> <true/> <key>StartInterval</key> <integer>21600</integer> </dict> </plist> [/sourcecode]

Then finally, to get it going without a reboot needed:

[sourcecode language="bash" light="true"] launchctl load com.google.calendar.mine.plist [/sourcecode]

(If you run this again, the second time you'll get a message saying it is already loaded).

It seems to work for me (admittedly, I've only just finished this - so there may be a bug which rears its head later) - but it seems to be okay. I do hope this is useful to you.