1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
// This program looks up words fromm Wiktionary, and creates Anki flashcards
// from them.
package main
import (
"bytes"
"encoding/json"
"io"
"log"
"net/http"
"os"
"time"
_ "github.com/mattn/go-sqlite3"
)
const (
rawDictionary = "/home/david/work/french-wiktionary-flashcards/raw-wiktextract-data.jsonl"
dictionary = "/home/david/work/french-wiktionary-flashcards/raw-wiktextract-data.sqlite3"
apiURL = "http://localhost:8765"
deckName = "Français"
modelName = "Basic-830ae"
)
type addNote struct {
Action string `json:"action"`
Version int `json:"version"`
Params addNoteParams `json:"params"`
}
type addNoteParams struct {
Note note `json:"note"`
}
type note struct {
DeckName string `json:"deckName"`
ModelName string `json:"modelName"`
// Fields will not be trivial to generalize
Fields fields `json:"fields"`
Options options `json:"options"`
}
type fields struct {
Front string `json:"Front"`
Back string `json:"Back"`
}
type options struct {
AllowDuplicate bool `json:"allowDuplicate"`
DuplicateScope string `json:"duplicateScope"`
}
func main() {
db, err := setupDatabase()
if err != nil {
log.Fatalf("setting up database: %s", err)
}
defer db.Close()
// We're going to start this app very simply! The first iteration will take
// a word as its first command-line argument. We will search for the word in
// the dictionary and create a new Anki card using the first exact match.
//
// In the future, we may make it easy for the user to edit cards (flag?),
// and possibly implement a TUI to choose definitions more interactively as
// well (e.g. search with partial matches).
//
// I would also like to make more things less hard-coded.
if len(os.Args) < 2 {
log.Fatalf("no word was provided")
}
word := os.Args[1]
var definition string
row := db.QueryRow(`select definition from words where word = ? limit 1`, word)
err = row.Scan(&definition)
if err != nil {
log.Fatalf("looking up '%s': %s", word, err)
}
c := http.DefaultClient
c.Timeout = 5 * time.Second
// Create the card
noteRequest := addNote{
Action: "addNote",
Version: 6,
Params: addNoteParams{
Note: note{
DeckName: deckName,
ModelName: modelName,
Fields: fields{
Front: word,
Back: definition,
},
Options: options{
AllowDuplicate: false,
DuplicateScope: "deck",
},
},
},
}
jsonBytes, err := json.Marshal(noteRequest)
if err != nil {
log.Fatalf("marshaling JSON: %s", err)
}
req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonBytes))
req.Header.Set("Content-Type", "application/json")
resp, err := c.Do(req)
if err != nil {
log.Fatalf("making request: %s", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var jsonResp struct {
Error string `json:"error"`
}
json.Unmarshal(body, &jsonResp)
if jsonResp.Error != "" {
log.Fatalf("creating card: %s", jsonResp.Error)
}
}
|