Last year I got into using Letterboxd, to complement my goal of watching more (good) movies . It’s got a really clean interface, the social features are useful but unobtrusive, and it makes remembering what I’ve watched and when I watched it easy. So why isn’t there a Letterboxd for books?
Funnily enough, Letterboxd still describes itself as “like GoodReads for movies”. But GoodReads itself is a mess. Take this screenshot of my childhood GoodReads account as an example:
Where do I log and review a book I’ve read? (The searchbar, but it takes half a dozen clicks and involves up to three different ways to log something). Where can I see the list of books I have read so I can recommend one to a friend? Where can I find books I plan to read? (Both under “My Books”, which by default shows them inter-mixed). Why is so much of the UI taken up with stuff like reading challenges and newsletters? Storygraph, leading independent alternative to GoodReads, has similar problems . These interfaces don’t lead me to log books; instead I just have some files in Obsidian that I sometimes remember to update.
Search
So let’s build our own GoodReads, with a UI that’s convenient enough to actually use. First we gotta build a search function for books. Then–
Wait, a search function for books. How do we do that? Well there’s the Google Books API, and it’s free which is nice. But when I search for “The Last Unicorn” (and do a little munging of the contents with jq ):
$ curl -X GET 'https://www.googleapis.com/books/v1/volumes?q=The+Last+Unicorn' | jq ".items | .[] | .volumeInfo | {title: .title, authors: .authors, isbns: .industryIdentifiers | map(.identifier) }"
I get this mess:
{ "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "9780451450524" , "0451450523" ] } { "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "1417644931" , "9781417644933" ] } { "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "9780593547342" , "0593547349" ] } { "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "0345028929" , "9780345028921" ] } { "title" : "The Last Unicorn" , "authors" : [ "Jane Elizabeth Cammack" ] , "isbns" : [ "8853010932" , "9788853010933" ] } { "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "1596060832" , "9781596060838" ] } { "title" : "Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "1399606972" , "9781399606974" ] } { "title" : "Peter S. Beagle's “The Last Unicorn”" , "authors" : [ "Timothy S. Miller" ] , "isbns" : [ "9783031534256" , "3031534255" ] } { "title" : "The Last Unicorn the Lost Journey" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "1616963085" , "9781616963088" ] } { "title" : "The Last Unicorn" , "authors" : [ "Peter S. Beagle" ] , "isbns" : [ "1616963182" , "9781616963187" ] }
Uh-oh. Why do we have so many distinct versions of The Last Unicorn? Well, each distinct format of a work has its own ISBN (so a hardcover, paperback, and eBook all have different ISBNs), even though the text may be identical. Then different editions (for example, a new foreword for a classic novel) all have their own set of unique ISBNs. Any given book may have dozens of ISBNs, each with their own unique entry in this API. That’s not going to work well for a search function: I just want to record that I read a book, not meticulously select which version of a book I read.
... continue reading