Commit 0d772490fa81
Changed files (16)
pkgs
systems
kyushu
tools
go-org-readwise
internal
org
readwise
pkgs/default.nix
@@ -15,7 +15,6 @@ in
vde-thinkpad = pkgs.callPackage ./my/vde-thinkpad { };
bekind = pkgs.callPackage ../tools/bekind { };
battery-monitor = pkgs.callPackage ../tools/battery-monitor { };
- go-org-readwise = pkgs.callPackage ../tools/go-org-readwise { };
ape = pkgs.callPackage ./ape { };
ram = pkgs.callPackage ./ram { };
govanityurl = pkgs.callPackage ./govanityurl { };
systems/kyushu/extra.nix
@@ -111,7 +111,7 @@
environment.systemPackages = with pkgs; [
kanata
nixos-rebuild-ng
- go-org-readwise
+ # go-org-readwise # FIXME: will add it back from its new place.
battery-monitor
# backup
restic # TODO: will probably move this to it's own configuration some day
tools/go-org-readwise/internal/org/testdata/test.org
@@ -1,104 +0,0 @@
-#+title: denote
-#+date: [2023-11-20 Mon 12:31]
-#+filetags: :emacs:notes:orgmode:
-#+identifier: 20231120T123124
-#+category: denote
-
-It is an [[denote:20231120T152341][emacs]] package that allows you to link to files in your org-mode documents.
-
-* Thoughts
-
-The presence of the tags in the filename seem to be both nice and bad at the same time. I
-think time will tell.
-
-* Links
-
-- https://takeonrules.com/2022/10/01/exploring-the-denote-emacs-package/
- Really interesting, simple take
-- https://takeonrules.com/2022/11/19/project-dispatch-menu-with-org-mode-metadata-denote-and-transient/
-- https://lucidmanager.org/productivity/taking-notes-with-emacs-denote/
-
-** [[https://baty.blog/2022/keeping-my-org-agenda-updated/][Keeping my Org Agenda updated based on Denote keywords - Jack Baty]]
-[2024-02-28 Wed 16:14]
-
-* Dynamic blocks
-
-Old regexp "md\\|org"
-
-#+BEGIN: denote-links :regexp "md"
-- [[denote:20230815T192545][2023-08-15]]
-- [[denote:20230929T113052][Always be quitting - Julio Merino (jmmv.dev)]]
-- [[denote:20230929T113053][Behavior Driven Development]]
-- [[denote:20230929T113054][Blog]]
-- [[denote:20230929T113058][Hyprland]]
-- [[denote:20230929T180738][A Practical Guide to Distributed Scrum]]
-- [[denote:20230929T180739][Culture & Empire]]
-- [[denote:20230929T180740][Debugging Teams]]
-- [[denote:20230929T180741][Getting Things Done]]
-- [[denote:20230929T180742][Inspired]]
-- [[denote:20230929T180743][Remote]]
-- [[denote:20230929T180744][Sleep Smarter]]
-- [[denote:20230929T180745][Staff Engineer]]
-- [[denote:20230929T180746][The Flinch]]
-- [[denote:20230929T180747][The Phoenix Project]]
-- [[denote:20230929T182110][Make Time]]
-- [[denote:20230930T094128][Actually, dark mode can save the planet]]
-- [[denote:20231005T185635][Build Tools Around Workflows, Not Workflows Around Tools]]
-- [[denote:20231006T080429][Counterculture in the Age of Hyperconnectivity]]
-- [[denote:20231006T080435][Don’t Use Stale Bots]]
-- [[denote:20231006T080443][Flake Schemas Making Flake Outputs Extensible · Determinate Systems]]
-- [[denote:20231006T080450][Flexibility]]
-- [[denote:20231006T080643][Beyond customization build tools that grow with us]]
-- [[denote:20231006T080657][40 Questions to Ask Yourself Every Year]]
-- [[denote:20231010T101856][DSLs Are a Waste of Time]]
-- [[denote:20231011T095229][Accept Interfaces Return Struct in Go [2018]]]
-- [[denote:20231016T095412][Choose Boring Technology]]
-- [[denote:20231016T095413][How I Made Peace With Automated Testing. Part 1 — You’re Using Too Many Mocks]]
-- [[denote:20231016T095414][How I Made Peace With Automated Testing. Part 2 - The Fun Tools Are Not Only Javascript]]
-- [[denote:20231017T185415][I Am No Longer Using Flakes]]
-- [[denote:20231019T082509][Concise Explanations Accelerate Progress]]
-- [[denote:20231028T145022][How I Get Things Done]]
-- [[denote:20231114T101657][Fast Path to Burnout - Delaying Deploys]]
-- [[denote:20231123T190449][Joining Getting Things Done and Building a Second Brain Philosophies]]
-- [[denote:20231129T185607][Building a Second Brain]]
-- [[denote:20231201T154535][Donald Knuth on work habits, problem solving, and happiness]]
-- [[denote:20231201T154630][Estimates are about time, so let's cut to the chase]]
-#+END:
-
-#+BEGIN: denote-links :regexp "_notes\\|_emacs"
-- [[denote:20231122T104723][granite, obsidian-like org-mode setup]]
-- [[denote:20231217T094656][Readwise org sync]]
-- [[denote:20231006T080643][Beyond customization build tools that grow with us]]
-- [[denote:20231120T123124][denote]]
-- [[denote:20231120T152341][Emacs]]
-- [[denote:20240119T151128][Obsidian]]
-- [[denote:20240119T151404][Obsidian plugins]]
-- [[denote:20240119T151801][Obsidian publishing]]
-#+END:
-
-#+BEGIN: denote-links :regexp ".*_notes"
-- [[denote:20231120T123124][denote]]
-- [[denote:20231120T152341][Emacs]]
-- [[denote:20240119T151128][Obsidian]]
-- [[denote:20240119T151404][Obsidian plugins]]
-- [[denote:20240119T151801][Obsidian publishing]]
-#+END:
-
-#+BEGIN: denote-links :regexp ".*_emacs"
-- [[denote:20231122T104723][granite, obsidian-like org-mode setup]]
-- [[denote:20231217T094656][Readwise org sync]]
-- [[denote:20231006T080643][Beyond customization build tools that grow with us]]
-- [[denote:20231120T123124][denote]]
-- [[denote:20231120T152341][Emacs]]
-#+END:
-
-* Alternatives
-
-** [[https://github.com/rtrppl/orgrr?tab=readme-ov-file][rtrppl/orgrr: Orgrr is a minimalist but complete note-taking system for Emacs. Its intended purpose is the creation and management of a Zettelkasten-like system.]]
-:PROPERTIES:
-:ID: baf739dc-66bc-4f50-aff4-1ef6a4bccc7e
-:END:
-[2023-11-22 Wed 16:32]
-
-** [[https://github.com/Kinneyzhang/gkroam][Kinneyzhang/gkroam: A lightweight roam replica on top of emacs org-mode.]]
-[2023-11-22 Wed 16:32]
tools/go-org-readwise/internal/org/org.go
@@ -1,38 +0,0 @@
-package org
-
-// Document is a "full" org-mode document, used for a new "readwise
-// document" containing highlights. The "full" notion here being, what
-// I need to sync from readwise to org, not the full representation of
-// a org file.
-type Document struct {
- Title string
- Author string
- Email string
- Date string
- FileTags []string
- Identifier string
- Category string
- URL string
- ReadwiseURL string
- Summary string
- Highlights []Highlight
-}
-
-// PartialDocument is a subset of org-mode used for an update of a
-// "readwise document", thus containing new highlights.
-type PartialDocument struct {
- Date string
- Highlights []Highlight
-}
-
-// Highlight represent a readwise highlight in org-mode.
-type Highlight struct {
- ID string
- URL string
- Location string
- LocationType string
- Date string
- Note string
- Text string
- Tags []string
-}
tools/go-org-readwise/internal/org/sync.go
@@ -1,200 +0,0 @@
-package org
-
-import (
- "context"
- "errors"
- "fmt"
- "os"
- "path/filepath"
- "regexp"
- "strings"
- "time"
-
- "github.com/vdemeester/home/tools/go-org-readwise/internal/readwise"
-)
-
-const (
- // denote-id-format "%Y%m%dT%H%M%S"
- denoteDateFormat = "20060102T150405"
- // org-date-format 2024-06-17 Mon 12:05
- orgDateFormat = "2006-01-02 Mon 15:04"
- // punctionation that is removed from file names.
- denoteExcludedPunctuationRegexpStr = "[][{}!@#$%^&*()=+'\"?,.|;:~`‘’“”/]*"
-)
-
-var (
- denoteExcludedPunctuationRegexp = regexp.MustCompile(denoteExcludedPunctuationRegexpStr)
- replaceHypensRegexp = regexp.MustCompile("[-]+")
-)
-
-func Sync(ctx context.Context, target string, results []readwise.Result) error {
- for _, result := range results {
- // FIXME: handle the case where tags where added after
- // a sync. In that case, we want to try different
- // titles (without tags, …) ; most likely we want to
- // use a regexp to "detect" part of the thing.
- denotefilename := denoteFilename(result)
- filename := filepath.Join(target, denotefilename)
- if _, err := os.Stat(filename); err == nil {
- // Append to the file
- p := createPartialOrgDocument(result)
- content, err := convertPartialDocument(p)
- if err != nil {
- return err
- }
- f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o600)
- if err != nil {
- return err
- }
- defer f.Close()
- if _, err = f.WriteString(string(content)); err != nil {
- return err
- }
- } else if errors.Is(err, os.ErrNotExist) {
- // Create the file
- d := createNewOrgDocument(result)
- content, err := convertDocument(d)
- if err != nil {
- return err
- }
- if err := os.WriteFile(filename, content, 0o644); err != nil {
- return err
- }
- } else {
- // Schrodinger: file may or may not exist. See err for details.
- // Therefore, do *NOT* use !os.IsNotExist(err) to test for file existence
- return err
- }
- }
- return nil
-}
-
-func createNewOrgDocument(r readwise.Result) Document {
- var filetags []string
- if len(r.BookTags) > 0 {
- filetags = make([]string, len(r.BookTags))
- for i, t := range r.BookTags {
- filetags[i] = sluggify(t.Name)
- }
- }
- return Document{
- Title: r.Title,
- Author: r.Author,
- ReadwiseURL: r.ReadwiseURL,
- URL: r.SourceURL,
- Email: "", // Figure out how to get the email
- Date: r.FirstHighlightDate().Format(orgDateFormat),
- Identifier: r.FirstHighlightDate().Format(denoteDateFormat),
- FileTags: filetags,
- Category: r.Category,
- Summary: r.Summary,
- Highlights: transformHighlights(r.Highlights),
- }
-}
-
-func createPartialOrgDocument(r readwise.Result) PartialDocument {
- now := time.Now()
- return PartialDocument{
- Date: now.Format(orgDateFormat),
- Highlights: transformHighlights(r.Highlights, func(h readwise.Highlight) bool {
- if h.HighlightedAt.After(now) {
- return true
- }
- return false
- }),
- }
-}
-
-func transformHighlights(highlights []readwise.Highlight, filters ...func(readwise.Highlight) bool) []Highlight {
- orgHighlights := []Highlight{}
- for _, h := range highlights {
- skip := false
- for _, filter := range filters {
- // If a filter returns false, skip the item
- if !filter(h) {
- skip = true
- break
- }
- }
- if skip {
- continue
- }
- var tags []string
- if len(h.Tags) > 0 {
- tags = make([]string, len(h.Tags))
- for i, t := range h.Tags {
- tags[i] = sluggify(t.Name)
- }
- }
- orgHighlights = append(orgHighlights, Highlight{
- ID: fmt.Sprintf("%d", h.ID),
- URL: h.ReadwiseURL,
- Date: h.HighlightedAt.Format(orgDateFormat),
- Note: h.Note,
- Text: h.Text,
- })
- }
- return orgHighlights
-}
-
-// See https://protesilaos.com/emacs/denote#h:4e9c7512-84dc-4dfb-9fa9-e15d51178e5d
-// DATE==SIGNATURE--TITLE__KEYWORDS.EXTENSION
-// Examples:
-// - 20240611T100401--tuesday-11-june-2024__journal.org
-// - 20240511T100401==readwise--foo__bar_baz.org
-func denoteFilename(result readwise.Result) string {
- var date, signature, title, keywords string
- // The DATE field represents the date in year-month-day format
- // followed by the capital letter T (for “time”) and the
- // current time in hour-minute-second notation. The
- // presentation is compact: 20220531T091625. The DATE serves
- // as the unique identifier of each note and, as such, is also
- // known as the file’s ID or identifier.
- date = result.FirstHighlightDate().Format(denoteDateFormat)
-
- // File names can include a string of alphanumeric characters
- // in the SIGNATURE field. Signatures have no clearly defined
- // purpose and are up to the user to define. One use-case is
- // to use them to establish sequential relations between files
- // (e.g. 1, 1a, 1b, 1b1, 1b2, …).
- // We use signature to mark files synced from readwise.
- signature = "==readwise=" + result.Category
-
- // The TITLE field is the title of the note, as provided by
- // the user. It automatically gets downcased by default and is
- // also hyphenated (Sluggification of file name
- // components). An entry about “Economics in the Euro Area”
- // produces an economics-in-the-euro-area string for the TITLE
- // of the file name.
- title = sluggify(result.Title)
-
- // The KEYWORDS field consists of one or more entries
- // demarcated by an underscore (the separator is inserted
- // automatically). Each keyword is a string provided by the
- // user at the relevant prompt which broadly describes the
- // contents of the entry.
- if len(result.BookTags) > 0 {
- tags := make([]string, len(result.BookTags))
- for i, t := range result.BookTags {
- tags[i] = sluggify(t.Name)
- }
- keywords = "__" + strings.Join(tags, "_")
- }
-
- return date + strings.ToLower(fmt.Sprintf("%s--%s%s.org", signature, title, keywords))
-}
-
-func sluggify(s string) string {
- // Remove punctuation
- s = denoteExcludedPunctuationRegexp.ReplaceAllString(s, "")
- // Replace spaces with hypens
- s = strings.ReplaceAll(s, " ", "-")
- // Replace underscore with hypens
- s = strings.ReplaceAll(s, "_", "-")
- // Replace multiple hypens with a single one
- s = replaceHypensRegexp.ReplaceAllString(s, "-")
- // Remove any leading and trailing hypen
- s = strings.TrimPrefix(s, "-")
- s = strings.TrimSuffix(s, "-")
- return s
-}
tools/go-org-readwise/internal/org/sync_test.go
@@ -1,34 +0,0 @@
-package org
-
-import "testing"
-
-func TestSluggify(t *testing.T) {
- testCases := []struct {
- input string
- expected string
- }{{
- input: "",
- expected: "",
- }, {
- input: "abcde",
- expected: "abcde",
- }, {
- input: "abcde---",
- expected: "abcde",
- }, {
- input: "a-b c--de",
- expected: "a-b-c-de",
- }, {
- input: "a_bc__de",
- expected: "a-bc-de",
- }, {
- input: "abcde$[)",
- expected: "abcde",
- }}
- for _, tc := range testCases {
- output := sluggify(tc.input)
- if output != tc.expected {
- t.Errorf("input \"%s\": expected %s, got %s", tc.input, tc.expected, output)
- }
- }
-}
tools/go-org-readwise/internal/org/write.go
@@ -1,83 +0,0 @@
-package org
-
-import (
- "bytes"
- "fmt"
- "strings"
- "text/template"
-)
-
-var (
- additionnalTemplate = `{{ if .Highlights }}* New Highlights on [{{ .Date }}]
-{{ range $h := .Highlights -}}
-** [{{ $h.Date }}] Highlight [[{{ $h.URL }}][{{ $h.ID }}]]{{ if $h.Tags }} {{ orgtags $h.Tags }}{{ end }}
-{{ $h.Text }}
-{{ if $h.Note }}*** Note
-{{ $h.Note }}
-{{ end -}}
-{{ end }}{{ end }}`
-
- mainTemplate = `#+title: {{ .Title }}
-#+author: {{ .Author }}
-#+date: {{ .Date }}
-#+identifier: {{ .Identifier }}
-#+category: {{ .Category }}
-{{ if .FileTags }}#+filetags: {{ orgtags .FileTags }}{{ end }}
-#+property: READWISE_URL: {{ .ReadwiseURL }}
-{{ if .URL }}#+property: URL: {{ .URL }}{{ end }}
-
-{{ .Summary }}
-
-* Highlights
-{{ range $h := .Highlights -}}
-** [{{ $h.Date }}] Highlight [[{{ $h.URL }}][{{ $h.ID }}]]{{ if $h.Tags }} {{ orgtags $h.Tags }}{{ end }}
-{{ $h.Text }}
-{{ if $h.Note }}*** Note
-{{ $h.Note }}
-{{ end -}}
-{{ end -}}
-`
-)
-
-func orgtags(tags []string) string {
- if len(tags) == 0 {
- return ""
- }
- return fmt.Sprintf(":%s:", strings.Join(tags, ":"))
-}
-
-func convertDocument(d Document) ([]byte, error) {
- var err error
-
- funcMap := template.FuncMap{
- "orgtags": orgtags,
- }
-
- tmpl, err := template.New("org").Funcs(funcMap).Parse(mainTemplate)
- if err != nil {
- return []byte{}, err
- }
- var buff bytes.Buffer
- if err := tmpl.Execute(&buff, d); err != nil {
- return []byte{}, err
- }
- return buff.Bytes(), nil
-}
-
-func convertPartialDocument(d PartialDocument) ([]byte, error) {
- var err error
-
- funcMap := template.FuncMap{
- "orgtags": orgtags,
- }
-
- tmpl, err := template.New("org").Funcs(funcMap).Parse(additionnalTemplate)
- if err != nil {
- return []byte{}, err
- }
- var buff bytes.Buffer
- if err := tmpl.Execute(&buff, d); err != nil {
- return []byte{}, err
- }
- return buff.Bytes(), nil
-}
tools/go-org-readwise/internal/readwise/readwise.go
@@ -1,75 +0,0 @@
-package readwise
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "strings"
- "time"
-)
-
-const (
- exportEndpoint = "https://readwise.io/api/v2/export/?"
- FormatUpdatedAfter = "2006-01-02T15:04:05"
-)
-
-func FetchFromAPI(ctx context.Context, apikey string, updateAfter *time.Time) ([]Result, error) {
- results := []Result{}
- httpClient := &http.Client{}
-
- var e Export
- var err error
- var nextPageCursor *int = nil
- for {
- e, err = fetchExport(ctx, httpClient, apikey, updateAfter, nextPageCursor)
- if err != nil {
- return results, err
- }
- results = append(results, e.Results...)
- nextPageCursor = e.NextPageCursor
- if nextPageCursor == nil {
- // No more pages to fetch, we get out
- break
- }
- }
-
- return results, nil
-}
-
-func fetchExport(ctx context.Context, client *http.Client, apikey string, updateAfter *time.Time, nextPageCursor *int) (Export, error) {
- export := Export{}
- endpoint := exportEndpoint
- params := []string{}
- if updateAfter != nil {
- params = append(params, "updatedAfter="+updateAfter.Format(FormatUpdatedAfter))
- }
- if nextPageCursor != nil {
- params = append(params, fmt.Sprintf("pageCursor=%d", *nextPageCursor))
- }
- endpoint = endpoint + strings.Join(params, "&&")
- req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil)
- if err != nil {
- return export, err
- }
- req.Header.Add("Authorization", "Token "+apikey)
- resp, err := client.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
-}
tools/go-org-readwise/internal/readwise/types.go
@@ -1,57 +0,0 @@
-package readwise
-
-import "time"
-
-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"`
-}
-
-func (r Result) FirstHighlightDate() *time.Time {
- if len(r.Highlights) == 0 {
- return nil
- }
- var t time.Time
- for _, h := range r.Highlights {
- if h.HighlightedAt.After(t) {
- t = h.HighlightedAt
- }
- }
- return &t
-}
-
-type Highlight struct {
- Text string `json:"text"`
- ID int `json:"id"`
- Note string `json:"note"`
- ReadwiseURL string `json:"readwise_url"`
- HighlightedAt time.Time `json:"highlighted_at"`
- BookID int `json:"book_id"`
- URL string `json:"url"`
- Color string `json:"color"`
- Updated time.Time `json:"updated"`
- Tags []Tag `json:"tags"`
-}
-
-type Tag struct {
- ID int `json:"id"`
- Name string `json:"name"`
-}
tools/go-org-readwise/.gitignore
@@ -1,1 +0,0 @@
-/go-org-readwise
\ No newline at end of file
tools/go-org-readwise/default.nix
@@ -1,7 +0,0 @@
-{ buildGoModule }:
-
-buildGoModule rec {
- name = "go-org-readwise";
- src = ./.;
- vendorHash = null;
-}
tools/go-org-readwise/go.mod
@@ -1,3 +0,0 @@
-module github.com/vdemeester/home/tools/go-org-readwise
-
-go 1.22
tools/go-org-readwise/go.sum
tools/go-org-readwise/main.go
@@ -1,63 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "log"
- "os"
- "path/filepath"
- "time"
-
- "github.com/vdemeester/home/tools/go-org-readwise/internal/org"
- "github.com/vdemeester/home/tools/go-org-readwise/internal/readwise"
-)
-
-func main() {
- apiKeyFile := flag.String("apiKeyFile", "", "File to load the apiKey from. If empty, it will defer to the READWISE_KEY environment variable")
- targetFolder := flag.String("targetFolder", "", "Folder to write highlights (in org file) into")
- flag.Parse()
-
- if *targetFolder == "" {
- log.Fatal("-targetFolder is a required flag")
- }
-
- apiKeyData, err := os.ReadFile(*apiKeyFile)
- if err != nil && !os.IsNotExist(err) {
- log.Fatalf("Error reading apiKeyFile %s: %v", *apiKeyFile, err)
- }
- apikey := string(apiKeyData)
- if apikey == "" {
- apikey = os.Getenv("READWISE_KEY")
- }
-
- stateFile := filepath.Join(*targetFolder, ".readwise-sync.state")
- updateAfter, err := getUpdateAfterFromFile(stateFile)
- if err != nil {
- log.Fatalf("Error reading readwise state file from %s: %v", stateFile, err)
- }
- ctx := context.Background()
- results, err := readwise.FetchFromAPI(ctx, apikey, updateAfter)
- if err != nil {
- log.Fatalf("Error while fetching results: %v", err)
- }
-
- if err := org.Sync(ctx, *targetFolder, results); err != nil {
- log.Fatalf("Error syncing readwise and org file in %s folder: %v", *targetFolder, err)
- }
-}
-
-func getUpdateAfterFromFile(stateFile string) (*time.Time, error) {
- data, err := os.ReadFile(stateFile)
- if err != nil && !os.IsNotExist(err) {
- return nil, err
- }
- // If the file doesn't exists, do not fail
- if os.IsNotExist(err) {
- return nil, nil
- }
- t, err := time.Parse(readwise.FormatUpdatedAfter, string(data))
- if err != nil {
- return nil, err
- }
- return &t, nil
-}
tools/go-org-readwise/README.org
@@ -1,27 +0,0 @@
-#+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
-
-
-* Tasks
-
-** TODO Explore =v3= API
-
-In theory I could rely on the =v3= API to get documents that are "archived" but have no
-highlights. Not sure this is something I want to do though.
-
-I doesn't have highlight so… I would have to query both.
-
-See https://readwise.io/reader_api.
README.org
@@ -151,7 +151,6 @@
**** Development Tools
- =bekind= - CLI tool for managing kind (Kubernetes in Docker) clusters with profile support
- =battery-monitor= - System battery monitoring utility
-- =go-org-readwise= - Integration between Org mode and Readwise
- =govanityurl= - Go vanity URL service
- =manifest-tool= - Container manifest tool