├── .gitignore ├── config.json ├── README.md ├── 300replacements ├── 300words └── asl_to_anki.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "words_file" : "300words", 3 | "links_file" : "300replacements", 4 | "deck_name" : "itsabijection HANDSPEAK 300 Signs for Beginners", 5 | "output_name" : "asl300", 6 | "eng_to_asl" : "True", 7 | "asl_to_eng" : "True" 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This lets you programmatically create Anki cards from HANDSPEAK. 2 | If you would just like the 300 signs in the file, please [download them here](https://ankiweb.net/shared/by-author/1700513665). 3 | 4 | There are broadly two ways to use this tool: 5 | 6 | # Completely automated 7 | Fill a file with a list of words, one word per line. Set the ```words_file``` field in config.json to this file name. Set the ```links_file``` to ''. Run ```python3 asl_to_anki.py config.json```. Expect some words not to be able to be found. This brings us to the next way. 8 | # With manual replacements 9 | If ```links_file``` is not set to "", the code will use the link provided to find the gif for the word provided. This overwrites the link that the program guesses at when a link is not manually provided, so if you have many errors you can add the correct links and restart to avoid manually merging decks. 10 | 11 | # Other parameters 12 | - ```deck_name```: what the deck appears as in Anki 13 | - ```output_name```: the name of the ```.apkg``` file 14 | - ```eng_to_asl```: set to ```True``` if you want cards where the front is english and the back is ASL 15 | - ```asl_to_eng```: the opposite 16 | 17 | The last two options are **NOT** mutually exclusive. 18 | -------------------------------------------------------------------------------- /300replacements: -------------------------------------------------------------------------------- 1 | { 2 | "fine, good":"https://www.handspeak.com/word/793/", 3 | "give":"https://www.handspeak.com/word/910/", 4 | "ok, okay":"https://www.handspeak.com/word/1545/", 5 | "old":"https://www.handspeak.com/word/1547/", 6 | "same":"https://www.handspeak.com/word/2628/", 7 | "sign, signed word":"https://www.handspeak.com/word/1965/", 8 | "time":"https://www.handspeak.com/word/2223/", 9 | "close":"https://www.handspeak.com/word/407/", 10 | "cold":"https://www.handspeak.com/word/416/", 11 | "early":"https://www.handspeak.com/word/640/", 12 | "fast":"https://www.handspeak.com/word/754/", 13 | "gone":"https://www.handspeak.com/word/3985/", 14 | "inform":"https://www.handspeak.com/word/1121/", 15 | "last":"https://www.handspeak.com/word/1234/", 16 | "leave":"https://www.handspeak.com/word/1253/", 17 | "mean, meaning":"https://www.handspeak.com/word/1364/", 18 | "right":"https://www.handspeak.com/word/1836/", 19 | "run":"https://www.handspeak.com/word/1859/", 20 | "anything":"https://www.handspeak.com/word/92/", 21 | "ASL - American Sign Language":"https://www.handspeak.com/word/120/", 22 | "close, close by, close to":"https://www.handspeak.com/word/4049/", 23 | "everyday":"https://www.handspeak.com/word/696/", 24 | "hear":"https://www.handspeak.com/word/126/", 25 | "if":"https://www.handspeak.com/word/1096/", 26 | "offspring":"https://www.handspeak.com/word/384/", 27 | "spring":"https://www.handspeak.com/word/2055/", 28 | "yet, not yet":"https://www.handspeak.com/word/2445/" 29 | } 30 | -------------------------------------------------------------------------------- /300words: -------------------------------------------------------------------------------- 1 | again 2 | also 3 | ask 4 | bad 5 | boy 6 | but 7 | can 8 | come 9 | deaf 10 | different 11 | drink 12 | drive 13 | eat 14 | email 15 | excuse 16 | family 17 | feel 18 | few 19 | find 20 | fine, good 21 | fingerspelling 22 | finish 23 | food 24 | for 25 | forget 26 | friend 27 | get 28 | girl 29 | give 30 | go 31 | good 32 | have, has, had 33 | he 34 | hearing 35 | hello 36 | help 37 | home 38 | how 39 | Internet 40 | know 41 | later 42 | like (feeling) 43 | little 44 | live, alive 45 | man 46 | many 47 | me 48 | meet 49 | more 50 | my 51 | name 52 | need 53 | new 54 | no 55 | not 56 | now 57 | ok, okay 58 | old 59 | other 60 | please 61 | remember 62 | same 63 | say 64 | school 65 | see 66 | she 67 | should 68 | sign, signed word 69 | slow 70 | some 71 | sorry 72 | store 73 | take 74 | tell 75 | text, sms 76 | thank, thank you 77 | their 78 | they 79 | think 80 | time 81 | tired 82 | try 83 | understand 84 | use, utilize 85 | wait 86 | want 87 | what 88 | when 89 | where 90 | which 91 | who 92 | why 93 | will 94 | with 95 | woman 96 | work 97 | write 98 | yes 99 | you 100 | your 101 | about 102 | after 103 | against 104 | answer 105 | any 106 | arrive 107 | beautiful 108 | because 109 | before 110 | better 111 | big 112 | bring 113 | busy 114 | buy 115 | change 116 | cleanse 117 | close 118 | cold 119 | color 120 | day 121 | early 122 | easy 123 | enough 124 | every 125 | false 126 | far 127 | fast 128 | follow 129 | from 130 | gone 131 | happy 132 | hard 133 | here 134 | hot 135 | hurt 136 | improve 137 | in 138 | inform 139 | interpreter 140 | keep 141 | last 142 | late 143 | learn 144 | leave 145 | look for 146 | lot, a lot 147 | make 148 | mean, meaning 149 | minute 150 | month 151 | morning 152 | most 153 | must 154 | near 155 | never 156 | next 157 | night 158 | nothing 159 | only 160 | open 161 | opposite 162 | out 163 | people 164 | plan 165 | practice 166 | prefer 167 | question 168 | read 169 | ready 170 | rest 171 | right 172 | run 173 | sad 174 | send 175 | show 176 | sit 177 | sleep 178 | small 179 | something 180 | sometimes 181 | start 182 | stay 183 | still 184 | stop 185 | support 186 | talk 187 | teach 188 | than 189 | thing 190 | today 191 | toilet 192 | tomorrow 193 | true 194 | until 195 | visit 196 | walk 197 | warm 198 | watch 199 | wrong 200 | yesterday 201 | accept 202 | afternoon 203 | agree 204 | allow 205 | almost 206 | alone 207 | always 208 | and 209 | angry 210 | animal 211 | anything 212 | argue 213 | ASL - American Sign Language 214 | attitude 215 | autumn 216 | average 217 | avoid 218 | away 219 | basic 220 | believe, belief 221 | best 222 | book 223 | both 224 | brother 225 | calm 226 | car 227 | class 228 | close, close by, close to 229 | comfortable 230 | deep, depth 231 | doubt 232 | English 233 | everyday 234 | everything 235 | example 236 | father 237 | funny 238 | game 239 | gift 240 | grow 241 | guess 242 | happen 243 | hear 244 | hold 245 | house 246 | idea 247 | if 248 | important 249 | include 250 | joke 251 | letter 252 | life 253 | look like 254 | lose, loss 255 | love 256 | money 257 | mother 258 | move 259 | movie 260 | normal 261 | number 262 | offspring 263 | outside 264 | overlook 265 | paper 266 | party 267 | pay 268 | pen 269 | picture 270 | play 271 | problem 272 | room 273 | safe 274 | sell 275 | service 276 | share 277 | sick 278 | since 279 | sister 280 | smart 281 | soon 282 | spring 283 | story 284 | struggle 285 | study 286 | summer 287 | sure 288 | that 289 | travel 290 | wash 291 | water 292 | week 293 | weekend 294 | winter 295 | wish 296 | word 297 | worse 298 | yet, not yet 299 | young 300 | yourself 301 | -------------------------------------------------------------------------------- /asl_to_anki.py: -------------------------------------------------------------------------------- 1 | import genanki 2 | import os 3 | import requests 4 | from slugify import slugify 5 | from moviepy.editor import VideoFileClip as VC 6 | from sys import argv 7 | import json 8 | 9 | config = argv[1] 10 | with open(config, "r") as f: 11 | config = json.loads(f.read()) 12 | 13 | def get_words(config): 14 | if config["words_file"] == "": 15 | assert config["links_file"] != "", "At least one of words_file, links_file should be non empty" 16 | return [] 17 | else: 18 | fname = config["words_file"] 19 | with open(fname, "r") as f: 20 | words = [x[:-1] for x in f.readlines()] 21 | return words 22 | 23 | def extract_mp4(L): 24 | from bs4 import BeautifulSoup as bs 25 | soup = bs(requests.get(L).content) 26 | return "https://www.handspeak.com" + soup.find_all("video", {"class": "v-asl"})[0].get("src") 27 | 28 | def get_links(words, config): 29 | links = {} 30 | for word in words: 31 | w = word.split(" ")[0].lower() 32 | if w[-1]==",": 33 | w = w[:-1] 34 | links[word] = f"http://www.handspeak.com/word/{w[0]}/{w[:3]}/{w}.mp4" 35 | if config["links_file"] != "": 36 | fname = config["links_file"] 37 | with open(fname, "r") as f: 38 | l = json.loads(f.read()) 39 | for w in l.keys(): 40 | links[w] = extract_mp4(l[w]) 41 | return links 42 | 43 | def dl_gifs(links): 44 | gifs = {} 45 | fname = config["words_file"] + config["links_file"] 46 | directory = f"./.{fname}_output" 47 | if not os.path.exists(directory): 48 | os.makedirs(directory) 49 | for word in links: 50 | try: 51 | link = links[word] 52 | with open(f"{directory}/{slugify(word)}.mp4", "wb") as f: 53 | f.write(requests.get(link).content) 54 | mp4 = VC(f"{directory}/{slugify(word)}.mp4") 55 | mp4.write_gif(f"{directory}/{slugify(word)}.gif", fps=10,program='imageio', verbose = False, logger = None) 56 | gifs[word] = f"{slugify(word)}.gif" 57 | os.remove(f"{directory}/{slugify(word)}.mp4") 58 | except: 59 | print(f"Couldn't get {word}. See readme") 60 | return directory, gifs 61 | 62 | def make_deck(gifs, direc, config): 63 | card = genanki.Model( 64 | 1380120062, 65 | 'card', 66 | fields=[ 67 | {'name': 'front'}, 68 | {'name': 'back'}, 69 | ], 70 | templates=[ 71 | { 72 | 'name': 'Card', 73 | 'qfmt': '
{{front}}
', 74 | 'afmt': """
{{FrontSide}}

{{back}}
""", 75 | }], 76 | css = """ 77 | .center{ 78 | width : fit-content; 79 | margin : auto; 80 | min-height : 100px; 81 | } 82 | """ 83 | ) 84 | 85 | deck = genanki.Deck( 86 | 2059400192, 87 | config["deck_name"]) 88 | for word in gifs: 89 | gif = gifs[word] 90 | if config["eng_to_asl"].lower() == "true": 91 | note = genanki.Note( 92 | model=card, 93 | fields=[word, f""], 94 | tags = ["eng_to_asl"]) 95 | deck.add_note(note) 96 | if config["asl_to_eng"].lower() == "true": 97 | note = genanki.Note( 98 | model=card, 99 | fields=[f"", word], 100 | tags = ["asl_to_eng"]) 101 | deck.add_note(note) 102 | 103 | package = genanki.Package(deck) 104 | package.media_files = [f"{direc}/{gifs[word]}" for word in gifs] 105 | return package 106 | 107 | words = get_words(config) 108 | links = get_links(words, config) 109 | direc, gifs = dl_gifs(links) 110 | package = make_deck(gifs, direc, config) 111 | package.write_to_file(f"{config['output_name']}.apkg") 112 | 113 | for f in os.listdir(direc): 114 | os.remove(f"{direc}/{f}") 115 | os.rmdir(direc) 116 | --------------------------------------------------------------------------------