├── .gitignore
├── titles.sql
├── bin
├── wikiogg
├── cloze
├── translate
├── add-audio
└── export
├── extract.sql
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | output
--------------------------------------------------------------------------------
/titles.sql:
--------------------------------------------------------------------------------
1 | SELECT title FROM book_info;
2 |
--------------------------------------------------------------------------------
/bin/wikiogg:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | default_lang='en'
4 |
5 | ogg=$(curl -s "https://${FROM_LANG-$default_lang}.wiktionary.org/wiki/${1}" | egrep -o '//upload.wikimedia.org[^"]+?ogg' | head -n1)
6 | curl -s "https:$ogg"
7 |
--------------------------------------------------------------------------------
/bin/cloze:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | tab=$'\t'
4 |
5 | while read line; do
6 | word=$(echo "$line" | cut -f2)
7 | text=$(echo "$line" | cut -f3)
8 | echo "${line}${tab}$(echo "$text" | sed "s/$word/{{c1::&}}/g")"
9 | done
10 |
11 |
--------------------------------------------------------------------------------
/extract.sql:
--------------------------------------------------------------------------------
1 | SELECT
2 | words.stem, words.word, lookups.usage
3 | FROM lookups
4 | LEFT OUTER JOIN book_info
5 | ON lookups.book_key=book_info.id
6 | LEFT OUTER JOIN words
7 | ON lookups.word_key=words.id
8 | WHERE title = '#TITLE#';
9 |
--------------------------------------------------------------------------------
/bin/translate:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IFS=$'\n'
4 | default_lang='en'
5 |
6 | if [ "$FROM_LANG" ]; then
7 | # from-to
8 | lang="$FROM_LANG-${TO_LANG-$default_lang}"
9 | else
10 | # to
11 | lang="$default_lang"
12 | fi
13 |
14 | apikey='trnsl.1.1.20151015T080754Z.fac48f0d13a96c3a.c0c58058288c42ba40de8aec2b36d9d86c3adb1d'
15 | endpoint="https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apikey}&lang=${lang}"
16 |
17 | translated=$(curl -s -L -G "$endpoint" -X GET --data-urlencode "text=$(cat "$1" | cut -f1)" | cut -f10 -d '"' | sed 's/\\n/\
18 | /g' | sed 's/,//g')
19 |
20 | paste <(cat "$1" | ./bin/cloze) <(echo "$translated")
21 |
22 |
23 |
--------------------------------------------------------------------------------
/bin/add-audio:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IFS=$'\n'
4 | minimumsize=100
5 | wordsfile=$(mktemp)
6 | out='output/audio'
7 |
8 | mkdir -p "$out"
9 |
10 | for i in $(cat "$1" | cut -f1); do
11 | word=$(echo "$i" | cut -f2 -d ' ')
12 | oggfile="$(mktemp).ogg"
13 |
14 | ./bin/wikiogg "$word" > "$oggfile"
15 |
16 | actualsize=$(wc -c < "$oggfile")
17 | if [ $actualsize -ge $minimumsize ]; then
18 | ffmpeg -n -loglevel 0 -i "$oggfile" "$out/$i.mp3"
19 | echo "[sound:$i.mp3]" >> "$wordsfile"
20 | else
21 | echo ' ' >> "$wordsfile"
22 | fi
23 |
24 | rm "$oggfile"
25 | done
26 |
27 | paste "$1" "$wordsfile"
28 | rm -f "$wordsfile"
29 |
--------------------------------------------------------------------------------
/bin/export:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | IFS=$'\n'
4 | DB='/Volumes/Kindle/system/vocabulary/vocab.db'
5 | OUT='output'
6 |
7 | # Create the output directory
8 | mkdir -p "$OUT"
9 |
10 | # Iterate over all books
11 | for title in $(cat titles.sql | sqlite3 $DB -separator $'\t'); do
12 | echo "Extracting words from $title..."
13 |
14 | # Extract the look-ups
15 | FILE="$OUT/$title.txt"
16 | escaped=$(echo "$title" | sed "s/'/''/")
17 | cat extract.sql | sed "s/#TITLE#/$escaped/g" | sqlite3 $DB -separator $'\t' > "$FILE"
18 |
19 | WORDS_NUM=$(cat $FILE | wc -l)
20 | if [ $WORDS_NUM == 0 ]; then
21 | rm "$FILE";
22 | else
23 | echo "Extracted $WORDS_NUM words from $title."
24 | fi
25 | done
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kindle Flashcards
2 |
3 | 1. Plug Kindle into the computer.
4 | 2. Open the terminal.
5 | 3. Download this repository and navigate to its folder: `cd ./kindle-flashcards`.
6 | 4. Execute `./bin/export`. This will create files with words and quotes for each book and save them to `./output`.
7 | 5. To add translations, run `FROM_LANG=de TO_LANG=en ./bin/translate output/Schachnovelle.txt > flashcards.txt`.
8 | 7. ...
9 | 8. The flashcards are ready!
10 |
11 |
12 |
13 |
14 | ## Importing into Anki
15 | * Create a new deck or use an existing deck.
16 | * Import the flashcards file (File -> Import).
17 |
18 | The flashcards file looks like this:
19 | ```
20 | staubig staubig Sein langer grüner Umhang war staubig und verschlissen. Sein langer grüner Umhang war {{c1::staubig}} und verschlissen. dusty
21 | ```
22 |
23 | The file has five fields:
24 |
25 | 1. The base form of the word (i.e. infinitive for verbs, nominative singular for nouns etc).
26 | 2. The original word form.
27 | 3. The sentence where the word was encountered.
28 | 4. The same sentence with the word clozed out. See [Cloze Deletion](http://ankisrs.net/docs/manual.html#cloze-deletion) in the Anki manual.
29 | 5. The translation of the word.
30 |
31 | The final result may look like this:
32 |
33 | ## Adding audio
34 | You can also add recordings of words' pronunciations to your cards. Run the following command:
35 | ```
36 | ./bin/add-audio flashcards.txt > flashcards_with_audio.txt
37 | ```
38 | The audio will be saved into `./output/audio`. Copy the audio files into the Anki media collection directory (typically `~/Documents/Anki/User 1/collection.media`).
39 |
40 | Audio files are downloaded from Wiktionary and encoded from ogg to mp3. Please note that this requires `ffmpeg` to be installed on your system (e.g. `brew install ffmpeg`).
41 |
42 | However, you can simply add this JavaScript to your card layout to enable the built-in text-to-speech:
43 |
44 | ```
45 |
51 | ```
52 |
--------------------------------------------------------------------------------