In this post, I will show you how to review notes in Google docs by sending changes in notes to your mailbox.
What
Organizing information. I tend to write stuff down a lot. Things that I learn, books I read, etc. and I found out that paper does not allow me to Ctrl-F (or / or Ctrl-S or Ctrl-R. Sorry I don’t ^W) and is hard to carry around. It’s not easy to replicate paper and even worse: I have observed that when you edit one paper copy, the content on the other copies stays the same.
My solution was to write all of my notes in Google docs, and when I started doing so, I naturally started to complicate what I needed from my digital pen and paper: I hardly ever find the time to go over my previous notes, so why not make it a little easier to read every piece of note that I take at least once?
My solution? I thought that it would be convenient to receive an email containing my newest notes every night.
How
At first, I was planning to wrap this into a web app that everyone could use, but I remembered how I think of app developers/users who require/give unnecessary access to personal data, and I decided not to create another information honeypot.
The first roadblock was that Google drive API does not allow you to retrieve Google docs revisions. That would leave me to either generate the diffs myself, or program to a browser engine to acquire the revisions through the UI (similar to this unbelievably amazing piece of code). I lack superpowers so I chose to go with the former. (But to save my ego, I’m going to pretend that I did that to make the solution more versatile.)
To access the drive API, you have to use oauth2 and therefore need to go through the somewhat complex and slow process of creating a project in your Google developer dashboard and enable the drive API key for it. You’ll obtain a credentials.json that contains:
{
"installed": {
...
"client_id": "...",
"client_secret": "...",
...
}
}
So keep it safe.
You can then download (includes waiting for Google drive go API bindings to download the whole universe to satisfy its dependencies), compile and install digest by doing:
$ go get -v github.com/farnasirim/digest/cmd/digest
$ go install github.com/farnasirim/digest/cmd/digest
After which given that $GOPATH/bin is in your $PATH
, you’ll be able to execute digest --help
.
Remember that credentials.json file? Put it here:
$ mkdir -p ~/.digest/auth/
$ cp $PATH_TO_GOOGLE_DRIVE_CREDENTIALS ~/.digest/auth/
Your first execution will probably look something like:
# Note the leading space which will keep your bash history password-free.
$ digest --folder=$GOOGLE_DRIVE_FOLDER_NAME \
--smtp-user=you@domain.com \
--smtp-pass=yourpass \
--smtp-server-host=smtp.domain.com \
--persist-confs
where $GOOGLE_DRIVE_FOLDER_NAME is the name of the folder which contains all of your notes and preferably nothing else. (If you are organized (read: obsessive) enough to write everything in Google docs, and more importantly are willing to review what you write in a systematic manner, I assume that you have 10+ levels of nesting in your documents structure. Just use the name of the top level folder.)
Also, viper
allows you to seamlessly accept environment variables for the flags:
...
viper.BindPFlags(rootCmd.Flags())
viper.SetEnvPrefix("DIG")
viper.AutomaticEnv()
Which means $DIG_SMTP_PASS
conveniently can be set as an environment variable instead of passing in --smtp-pass=yourpass
.
And that’s it! This first execution takes the first snapshot, and does not yet send you an email. Your subsequent usages will probably look like this:
$ digest
This will send you an email containing the diff with the last snapshot. A snapshot is taken (and put in ~/.digest/data/) whenever digest
is successfully run. If no difference is found between two consecutive snapshots, you’ll enjoy some free panic in your email:
And the content of the email gets a little bit more interesting when you’ve actually applied some changes to your docs:
I issue the $ digest
command on my PC everyday, just before I call it a night and read the emailed diff on my phone on my way back home. However, if you only hang out with the very cool kids, you may already be thinking about:
# So you'll be motivated to finish by 23:30
30 23 * * * digest
Feed it to the cron engine on your ser… who am I kidding. If you’re into that kind of stuff, you already know how to work your magic.
Anyway, if digest fits in your routine, do tell me about it! Especially if it involves crazy automation scenarios (Bonus points if you manage to trigger it with your office door lock).
UPD: Again if the following condition is true about you, you won’t need no mortal’s guidance but if you’re a systemd
freak, you may want to use hooks to digest
your notes before a shutdown/hibernate.
Hint: DefaultDependencies
, oneshot
.
Internals
Here’s part of the project directory structure:
├── cmd
│ └── digest
│ ├── digest.go
│ └── main.go
├── diff
│ ├── diff.go
├── drive
│ ├── auth.go
│ ├── drive.go
├── smtp
│ ├── smtp.go
I have implemented the following services in their respective directories and have hooked everything up together (a little uglier than usual, I must say) in cmd/digest.
package digest
type DocsService interface {
TakeAndPersistSnapshopt(string) error
}
type SMTPService interface {
SendMail(to string, msg []byte) error
SendMailHtml(to, subject string, msg []byte) error
}
type DiffService interface {
DiffDirsHtml(string, string) string
}
I have used go modules for maintaining the dependencies of this project. If you haven’t heard of them, I suggest starting at Russ Cox’s talk on the subject.