commit ef7329caea0bc3f91af7dc3a8f1e1a216876e6fb
parent 26941459345894a188c1e655ef9fbf41e831a1c7
Author: Vincent Demeester <vincent@sbr.pm>
Date: Wed, 12 Jun 2024 19:15:24 +0200
tools: init go-org-readwise 📕
A tool to import readwise highlights into org mode.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Diffstat:
10 files changed, 165 insertions(+), 0 deletions(-)
diff --git a/nix/overlays/sbr.nix b/nix/overlays/sbr.nix
@@ -13,6 +13,7 @@ rec {
inherit (self) stdenv;
};
bekind = super.callPackage ../../tools/bekind { };
+ go-org-readwise = super.callPackage ../../tools/go-org-readwise { };
my = import ../packages {
inherit (self) pkgs;
diff --git a/nix/packages/default.nix b/nix/packages/default.nix
@@ -6,6 +6,7 @@ rec {
vrsync = pkgs.callPackage ./my/vrsync { };
vde-thinkpad = pkgs.callPackage ./my/vde-thinkpad { };
bekind = pkgs.callPackage ../../tools/bekind { };
+ go-org-readwise = pkgs.callPackage ../../tools/go-org-readwise { };
chmouzies.kubernetes = pkgs.callPackage ./chmouzies/kubernetes.nix { };
diff --git a/tools/go-org-readwise/.gitignore b/tools/go-org-readwise/.gitignore
@@ -0,0 +1 @@
+/go-org-readwise+
\ No newline at end of file
diff --git a/tools/go-org-readwise/README.org b/tools/go-org-readwise/README.org
@@ -0,0 +1,17 @@
+#+TITLE: `go-org-readwise`
+
+This is a very very simple project that sync from readwise API to a
+set of org files in a folder. It implements just what is needed from
+the [readwise API](https://readwise.io/api_deets) to work.
+
+* Readwise API
+
+We are /only/ going to implement the export part of the API as, this should be the only one
+we need.
+
+#+begin_quote
+If you want to pull all of the highlights from a user's account into your service (eg
+notetaking apps, backups, etc) this endpoint is all you need!
+#+end_quote
+
+
diff --git a/tools/go-org-readwise/default.nix b/tools/go-org-readwise/default.nix
@@ -0,0 +1,7 @@
+{ buildGoModule }:
+
+buildGoModule rec {
+ name = "go-org-readwise";
+ src = ./.;
+ vendorHash = null;
+}
diff --git a/tools/go-org-readwise/go.mod b/tools/go-org-readwise/go.mod
@@ -0,0 +1,3 @@
+module github.com/vdemeester/home/tools/go-org-readwise
+
+go 1.22
diff --git a/tools/go-org-readwise/internal/org/org.go b/tools/go-org-readwise/internal/org/org.go
@@ -0,0 +1 @@
+package org
diff --git a/tools/go-org-readwise/internal/readwise/readwise.go b/tools/go-org-readwise/internal/readwise/readwise.go
@@ -0,0 +1,45 @@
+package readwise
+
+// TODO:Â support pages
+
+import (
+ "context"
+ "encoding/json"
+ "io"
+ "net/http"
+ "time"
+)
+
+func FetchFromAPI(ctx context.Context, apikey string, updateAfter *time.Time) (Export, error) {
+ export := Export{}
+ endpoint := "https://readwise.io/api/v2/export"
+ if updateAfter != nil {
+ endpoint = endpoint + "/?updateAfter=" + updateAfter.Format(time.RFC3339)
+ }
+
+ httpClient := &http.Client{}
+
+ req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
+ if err != nil {
+ return export, err
+ }
+ req.Header.Add("Authorization", "Token "+apikey)
+ resp, err := httpClient.Do(req)
+ if err != nil {
+ return export, err
+ }
+
+ defer resp.Body.Close()
+
+ body, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return export, err
+ }
+
+ err = json.Unmarshal(body, &export)
+ if err != nil {
+ return export, err
+ }
+
+ return export, nil
+}
diff --git a/tools/go-org-readwise/internal/readwise/types.go b/tools/go-org-readwise/internal/readwise/types.go
@@ -0,0 +1,49 @@
+package readwise
+
+type Export struct {
+ Count int `json:"count"`
+ NextPageCursor *int `json:"nextPageCursor"`
+ Results []Result `json:"results"`
+}
+
+type Result struct {
+ UserBookId int `json:"use_book_id"`
+ Title string `json:"title"`
+ ReadableTitle string `json:"readable_title"`
+ CoverImageURL string `json:"cover_image_url"`
+ Author string `json:"author"`
+ UniqueURL string `json:"unique_url"`
+ BookTags []Tag `json:"book_tags"`
+ Category string `json:"category"`
+ DocumentNote string `json:"document_note"`
+ Summary string `json:"summary"`
+ ReadwiseURL string `json:"readwise_url"`
+ Source string `json:"source"`
+ SourceURL string `json:"source_url"`
+ Highlights []Highlight `json:"highlights"`
+}
+
+type Highlight struct {
+ Text string `json:"text"`
+ ID int `json:"id"`
+ Note string `json:"note"`
+ Location int `json:"location"`
+ LocationType string `json:"location_type"`
+ HighlightedAt string `json:"highlighted_at"`
+ BookID int `json:"book_id"`
+ URL string `json:"url"`
+ Color string `json:"color"`
+ Updated string `json:"updated"`
+ Tags []Tag `json:"tags"`
+}
+
+type Tags struct {
+ Count int `json:"count"`
+ Next string `json:"next"`
+ Results []Tag `json:"results"`
+}
+
+type Tag struct {
+ ID int `json:"id"`
+ Name string `json:"name"`
+}
diff --git a/tools/go-org-readwise/main.go b/tools/go-org-readwise/main.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "time"
+
+ "github.com/vdemeester/home/tools/go-org-readwise/internal/readwise"
+)
+
+func main() {
+ ctx := context.Background()
+ highlights, merr := readwise.FetchFromAPI(ctx, os.Getenv("READWISE_KEY"), nil)
+ if merr != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", merr)
+ os.Exit(1)
+ }
+ fmt.Println("count", highlights.Count)
+ fmt.Println("nextPageCursor", *highlights.NextPageCursor)
+ fmt.Println("size", len(highlights.Results))
+
+ updateAfter := time.Now().Add(-1000 * time.Hour)
+ fmt.Println("updateAfter:", updateAfter)
+ highlights, merr = readwise.FetchFromAPI(ctx, os.Getenv("READWISE_KEY"), &updateAfter)
+ if merr != nil {
+ fmt.Fprintf(os.Stderr, "%v\n", merr)
+ os.Exit(1)
+ }
+ fmt.Println("count", highlights.Count)
+ fmt.Println("nextPageCursor", *highlights.NextPageCursor)
+ fmt.Println("size", len(highlights.Results))
+ for _, h := range highlights.Results {
+ fmt.Println("title", h.Title, len(h.Highlights), h.BookTags)
+ // for _, hh := range h.Highlights {
+ // fmt.Println(">>>", hh.ID, hh.Tags)
+ // }
+ }
+}