Org Mode: Format Libby book highlights exported as JSON
| emacs, orgThe Toronto Public Library (and many other libraries) offers e-book access through Overdrive, which I can read through the Libby app on my phone. It turns out that I can select passages to highlight. It also turns out that I can use the Reading Journey view to export the highlights as JSON, even for books I've returned. This is what the JSON looks like.
{ "version": 1, "readingJourney": { "cover": { "contentType": "image/jpeg", "url": "https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg", "title": "How to Take Smart Notes", "color": "#D9D9D9", "format": "ebook" }, "title": { "text": "How to Take Smart Notes", "url": "https://share.libbyapp.com/title/5796521", "titleId": "5796521" }, "author": "Sönke Ahrens", "publisher": "Sönke Ahrens", "isbn": "9781393776819", "percent": 0.313229455252918 }, "highlights": [ { "timestamp": 1729898852000, "chapter": "13 Share Your Insight", "percent": 0.824912451361868, "color": "#FFB", "quote": "For every document I write, I have another called “xy-rest.doc,” and every single time I cut something, I copy it into the other document, convincing myself that I will later look through it and add it back where it might fit. Of" }, { "timestamp": 1729898760000, "chapter": "13 Share Your Insight", "percent": 0.801566108949416, "color": "#FFB", "quote": "I always work on different manuscripts at the same time. With this method, to work on different things simultaneously, I never encounter any mental blockages" }, ... ] }
I want to save those highlights in my books.org
file for easy searching, grouping the highlights
by chapter. The following code helps with that:
(defun my-org-insert-book-highlights-from-libby (url) (interactive "MURL: ") (let-alist (plz 'get url :as #'json-read) (insert "* " .readingJourney.title.text " - " .readingJourney.author "\n") (org-set-property "ISBN" .readingJourney.isbn) (org-set-property "COVER" .readingJourney.cover.url) (org-set-property "TITLE" .readingJourney.title.text) (org-set-property "AUTHOR" .readingJourney.author) (insert (org-link-make-string .readingJourney.title.url .readingJourney.cover.url) "\n") ;; sort the highlights by chapter (insert (mapconcat (lambda (row) (concat "** " (replace-regexp-in-string " +" " " (car row)) "\n" (mapconcat (lambda (quote) (concat "#+begin_quote\n" (alist-get 'quote quote) "\n#+end_quote\n\n")) (cdr row) "") "\n\n")) (seq-group-by (lambda (o) (alist-get 'chapter o)) (sort .highlights :key (lambda (o) (alist-get 'percent o))))))))
This is what the resulting document looks like:
* How to Take Smart Notes - Sönke Ahrens :PROPERTIES: :ISBN: 9781393776819 :COVER: https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg :TITLE: How to Take Smart Notes :AUTHOR: Sönke Ahrens :END: https://img1.od-cdn.com/ImageType-100/7635-1/{B41A3269-BC2A-4497-8C71-0A3F1FA3C694}Img100.jpg ** 1 Everything You Need to Know #+begin_quote never force myself to do anything I don’t feel like. Whenever I am stuck, I do something else.” #+end_quote #+begin_quote Luhmann’s only real help was a housekeeper who cooked for him and his children during the week, not that extraordinary considering he had to raise three children on his own after his wife died early. #+end_quote ...
This is part of my Emacs configuration.
You can comment with Disqus or you can e-mail me at sacha@sachachua.com.