@ -1,4 +0,0 @@ | |||||
node_modules/ | |||||
/wanikani.json | |||||
/wanikani.yaml | |||||
/radicals.yaml |
@ -1,232 +0,0 @@ | |||||
import axios from 'axios' | |||||
import rateLimit, { RateLimitedAxiosInstance } from 'axios-rate-limit' | |||||
/** | |||||
* https://docs.api.wanikani.com/20170710/#rate-limit | |||||
* | |||||
* Requests per minute 60 | |||||
* | |||||
* @param apiKey @default process.env['WANIKANI_API_KEY'] | |||||
* @returns | |||||
*/ | |||||
export function makeWanikani( | |||||
apiKey = process.env['WANIKANI_API_KEY']! | |||||
): WaniKaniAxiosInstance { | |||||
const wkApi = rateLimit( | |||||
axios.create({ | |||||
baseURL: 'https://api.wanikani.com/v2/', | |||||
headers: { | |||||
Authorization: `Bearer ${apiKey}` | |||||
}, | |||||
validateStatus: function () { | |||||
return true | |||||
} | |||||
}), | |||||
{ | |||||
/** | |||||
* Per second | |||||
*/ | |||||
maxRequests: 1, | |||||
perMilliseconds: 1000 | |||||
} | |||||
) | |||||
return Object.assign(wkApi, { | |||||
async *kanji(params = {}) { | |||||
let nextUrl = '/subjects' | |||||
while (true) { | |||||
const r = await wkApi.get< | |||||
ICollection< | |||||
IResource<{ | |||||
characters: string | |||||
level: number | |||||
}> | |||||
> | |||||
>(nextUrl, { | |||||
params: { | |||||
...params, | |||||
types: 'kanji' | |||||
} | |||||
}) | |||||
for (const d of r.data.data) { | |||||
yield { | |||||
id: d.id, | |||||
level: d.data.level, | |||||
characters: d.data.characters | |||||
} | |||||
} | |||||
console.error(r.data.url) | |||||
nextUrl = r.data.pages.next_url || '' | |||||
if (!nextUrl) { | |||||
break | |||||
} | |||||
} | |||||
}, | |||||
async *vocabulary(params = {}) { | |||||
let nextUrl = '/subjects' | |||||
while (true) { | |||||
const r = await wkApi.get< | |||||
ICollection< | |||||
IResource<{ | |||||
characters: string | |||||
level: number | |||||
context_sentences: { | |||||
ja: string | |||||
en: string | |||||
}[] | |||||
}> | |||||
> | |||||
>(nextUrl, { | |||||
params: { | |||||
...params, | |||||
types: 'vocabulary' | |||||
} | |||||
}) | |||||
for (const d of r.data.data) { | |||||
yield { | |||||
id: d.id, | |||||
level: d.data.level, | |||||
characters: d.data.characters, | |||||
sentences: d.data.context_sentences | |||||
} | |||||
} | |||||
console.error(r.data.url) | |||||
nextUrl = r.data.pages.next_url || '' | |||||
if (!nextUrl) { | |||||
break | |||||
} | |||||
} | |||||
}, | |||||
async *subjects<T = any>(params = {}) { | |||||
let nextUrl = '/subjects' | |||||
while (true) { | |||||
const r = await wkApi.get< | |||||
ICollection< | |||||
IResource<any> & { | |||||
id: number | |||||
object: string | |||||
data_updated_at: string | |||||
url: string | |||||
data: T | |||||
} | |||||
> | |||||
>(nextUrl, { params }) | |||||
for (const d of r.data.data) { | |||||
yield { | |||||
id: d.id, | |||||
data_updated_at: d.data_updated_at, | |||||
object: d.object, | |||||
url: d.url, | |||||
data: d.data | |||||
} | |||||
} | |||||
console.error(r.data.url) | |||||
nextUrl = r.data.pages.next_url || '' | |||||
if (!nextUrl) { | |||||
break | |||||
} | |||||
} | |||||
}, | |||||
async *assignments( | |||||
params = { | |||||
unlocked: 'true' | |||||
} | |||||
) { | |||||
let nextUrl = '/assignments' | |||||
while (true) { | |||||
const r = await wkApi.get< | |||||
ICollection< | |||||
IResource<{ | |||||
subject_id: number | |||||
srs_stage: number | |||||
}> | |||||
> | |||||
>(nextUrl, { | |||||
params | |||||
}) | |||||
console.error(r.data.url) | |||||
for (const d of r.data.data) { | |||||
yield { | |||||
id: d.data.subject_id, | |||||
srsLevel: d.data.srs_stage | |||||
} | |||||
} | |||||
nextUrl = r.data.pages.next_url || '' | |||||
if (!nextUrl) { | |||||
break | |||||
} | |||||
} | |||||
} | |||||
}) | |||||
} | |||||
export interface WaniKaniAxiosInstance extends RateLimitedAxiosInstance { | |||||
kanji(params?: any): AsyncGenerator<{ | |||||
id: number | |||||
level: number | |||||
characters: string | |||||
}> | |||||
vocabulary(params?: any): AsyncGenerator<{ | |||||
id: number | |||||
level: number | |||||
characters: string | |||||
sentences: { | |||||
ja: string | |||||
en: string | |||||
}[] | |||||
}> | |||||
subjects<T = any>( | |||||
params?: any | |||||
): AsyncGenerator<{ | |||||
id: number | |||||
object: string | |||||
data_updated_at: string | |||||
url: string | |||||
data: T | |||||
}> | |||||
assignments(params?: any): AsyncGenerator<{ | |||||
id: number | |||||
srsLevel: number | |||||
}> | |||||
} | |||||
export interface IResource<T = any> { | |||||
id: number | |||||
url: string | |||||
data_updated_at: string // Date | |||||
data: T | |||||
} | |||||
export interface ICollection<T = any> { | |||||
object: string | |||||
url: string | |||||
pages: { | |||||
next_url?: string | |||||
previous_url?: string | |||||
per_page: number | |||||
} | |||||
total_count: number | |||||
data_updated_at: string // Date | |||||
data: T[] | |||||
} | |||||
export interface IError { | |||||
error: string | |||||
code: number | |||||
} |
@ -1,10 +0,0 @@ | |||||
{ | |||||
"extends": "../tsconfig.json", | |||||
"compilerOptions": { | |||||
"rootDir": ".", | |||||
"outDir": "../lib", | |||||
"sourceMap": true, | |||||
"declaration": true, | |||||
"declarationMap": true | |||||
} | |||||
} |
@ -1,192 +0,0 @@ | |||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. | |||||
# yarn lockfile v1 | |||||
"@cspotcode/source-map-consumer@0.8.0": | |||||
version "0.8.0" | |||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" | |||||
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== | |||||
"@cspotcode/source-map-support@0.7.0": | |||||
version "0.7.0" | |||||
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" | |||||
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== | |||||
dependencies: | |||||
"@cspotcode/source-map-consumer" "0.8.0" | |||||
"@tsconfig/node10@^1.0.7": | |||||
version "1.0.8" | |||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" | |||||
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== | |||||
"@tsconfig/node12@^1.0.7": | |||||
version "1.0.9" | |||||
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" | |||||
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== | |||||
"@tsconfig/node14@^1.0.0": | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" | |||||
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== | |||||
"@tsconfig/node16@^1.0.2": | |||||
version "1.0.2" | |||||
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" | |||||
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== | |||||
"@types/js-yaml@^4.0.5": | |||||
version "4.0.5" | |||||
resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" | |||||
integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== | |||||
"@types/json5@^0.0.29": | |||||
version "0.0.29" | |||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" | |||||
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= | |||||
"@types/node@^17.0.23": | |||||
version "17.0.23" | |||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.23.tgz#3b41a6e643589ac6442bdbd7a4a3ded62f33f7da" | |||||
integrity sha512-UxDxWn7dl97rKVeVS61vErvw086aCYhDLyvRQZ5Rk65rZKepaFdm53GeqXaKBuOhED4e9uWq34IC3TdSdJJ2Gw== | |||||
"@types/wanakana@^4.0.3": | |||||
version "4.0.3" | |||||
resolved "https://registry.yarnpkg.com/@types/wanakana/-/wanakana-4.0.3.tgz#b67b133b223facbf28aba0338b79f523e92cf97a" | |||||
integrity sha512-AibaWzahBKizxmsAy8rEWSIqqcT0v9KZTS8S6zPLmStGBFdccYfXydhgwYOV+6lGqQ890MpA4h2MPET3uPk9Zg== | |||||
acorn-walk@^8.1.1: | |||||
version "8.2.0" | |||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" | |||||
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== | |||||
acorn@^8.4.1: | |||||
version "8.7.0" | |||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" | |||||
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== | |||||
arg@^4.1.0: | |||||
version "4.1.3" | |||||
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" | |||||
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== | |||||
argparse@^2.0.1: | |||||
version "2.0.1" | |||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" | |||||
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== | |||||
axios-rate-limit@^1.3.0: | |||||
version "1.3.0" | |||||
resolved "https://registry.yarnpkg.com/axios-rate-limit/-/axios-rate-limit-1.3.0.tgz#03241d24c231c47432dab6e8234cfde819253c2e" | |||||
integrity sha512-cKR5wTbU/CeeyF1xVl5hl6FlYsmzDVqxlN4rGtfO5x7J83UxKDckudsW0yW21/ZJRcO0Qrfm3fUFbhEbWTLayw== | |||||
axios@^0.26.1: | |||||
version "0.26.1" | |||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" | |||||
integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== | |||||
dependencies: | |||||
follow-redirects "^1.14.8" | |||||
create-require@^1.1.0: | |||||
version "1.1.1" | |||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" | |||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== | |||||
diff@^4.0.1: | |||||
version "4.0.2" | |||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" | |||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== | |||||
follow-redirects@^1.14.8: | |||||
version "1.14.9" | |||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" | |||||
integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== | |||||
import-sort-parser-typescript@^6.0.0: | |||||
version "6.0.0" | |||||
resolved "https://registry.yarnpkg.com/import-sort-parser-typescript/-/import-sort-parser-typescript-6.0.0.tgz#98e73cef9e077d073e798722ed59e215b51c17e2" | |||||
integrity sha512-pgxnr3I156DonupQriNsgDb2zJN9TxrqCCIN1rwT/6SDO1rkJb+a0fjqshCjlgacTSA92oPAp1eAwmQUeZi3dw== | |||||
dependencies: | |||||
typescript "^3.2.4" | |||||
js-yaml@^4.1.0: | |||||
version "4.1.0" | |||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" | |||||
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== | |||||
dependencies: | |||||
argparse "^2.0.1" | |||||
json5@^1.0.1: | |||||
version "1.0.1" | |||||
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" | |||||
integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== | |||||
dependencies: | |||||
minimist "^1.2.0" | |||||
make-error@^1.1.1: | |||||
version "1.3.6" | |||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" | |||||
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== | |||||
minimist@^1.2.0, minimist@^1.2.6: | |||||
version "1.2.6" | |||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" | |||||
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== | |||||
strip-bom@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" | |||||
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= | |||||
ts-node@^10.7.0: | |||||
version "10.7.0" | |||||
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" | |||||
integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== | |||||
dependencies: | |||||
"@cspotcode/source-map-support" "0.7.0" | |||||
"@tsconfig/node10" "^1.0.7" | |||||
"@tsconfig/node12" "^1.0.7" | |||||
"@tsconfig/node14" "^1.0.0" | |||||
"@tsconfig/node16" "^1.0.2" | |||||
acorn "^8.4.1" | |||||
acorn-walk "^8.1.1" | |||||
arg "^4.1.0" | |||||
create-require "^1.1.0" | |||||
diff "^4.0.1" | |||||
make-error "^1.1.1" | |||||
v8-compile-cache-lib "^3.0.0" | |||||
yn "3.1.1" | |||||
tsconfig-paths@^3.14.1: | |||||
version "3.14.1" | |||||
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" | |||||
integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== | |||||
dependencies: | |||||
"@types/json5" "^0.0.29" | |||||
json5 "^1.0.1" | |||||
minimist "^1.2.6" | |||||
strip-bom "^3.0.0" | |||||
typescript@^3.2.4: | |||||
version "3.9.10" | |||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" | |||||
integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== | |||||
typescript@^4.6.3: | |||||
version "4.6.3" | |||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" | |||||
integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== | |||||
v8-compile-cache-lib@^3.0.0: | |||||
version "3.0.0" | |||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" | |||||
integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== | |||||
wanakana@^4.0.2: | |||||
version "4.0.2" | |||||
resolved "https://registry.yarnpkg.com/wanakana/-/wanakana-4.0.2.tgz#a7d60186724a56fd50e6e9c224628c09294901d8" | |||||
integrity sha512-lBFtnLJhTpp5wQBdH7TrOHhLxqmUabAfL86plNN8+iffyhosjZyx+kkO8KEBGR8zWH5nxSQ67oyx3W/lcEC8sg== | |||||
yn@3.1.1: | |||||
version "3.1.1" | |||||
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" | |||||
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== |
@ -0,0 +1,2 @@ | |||||
* | |||||
!.gitignore |
@ -0,0 +1,37 @@ | |||||
{ | |||||
"bItjzeqBPmkWrGM2PXVBq.png": "Samurai jackhammer", | |||||
"nBz6EnUddzNRfWyErhvJo.png": "World tree", | |||||
"mmFVt_hmOI8eQAVqTbuvK.png": "Sun over spikes", | |||||
"m-N12xyoIBVoA0m2WwX4J.png": "Triple power", | |||||
"AEWmIMzMKbkWeqlOLF9zs.png": "Windblown hat", | |||||
"1NGe9RRlX85hqTNp135bH.png": "Horns on heaven", | |||||
"dFjLYJGf6PGRzggq4S1QD.png": "Low ground", | |||||
"9_f2SydPR9C9LDVnQ9ZLu.png": "Standing tree", | |||||
"3Gl7bMaZmhynSWF1W0_er.png": "Wolverine on the stool", | |||||
"XRKYCD0gCrP9_hNRdKBpD.png": "Devil hat", | |||||
"tN4gkHYcwXylA88tbF9XE.png": "Broken center", | |||||
"7CEIB2YGrtklTVCrfvJaB.png": "Flow", | |||||
"sp1Ft5QclMXe_xR3e1Ftl.png": "Suitable flowery crown", | |||||
"d04-7IPtNrQyUDB_LKDZG.png": "Rice on the lion", | |||||
"fAoMUyYnY2xK5Llq4F0eW.png": "Horned lantern", | |||||
"Q-eiDxE9R8FfJZv-TOxUD.png": "Narrow RHS", | |||||
"IecTpX9kknAFleYjbyV9A.png": "Pi tree", | |||||
"QtszVbE-npm0WTjti6FgX.png": "Hooked arrow", | |||||
"889jkHz3dGQjosfCcVv84.png": "Stamping stool", | |||||
"kK0_4rI7XntWDB-s8g0xw.png": "Servant stool", | |||||
"m6ml0f_FQH1ZaYdqWIPgA.png": "Safety roof", | |||||
"tcvyrE7pinMdtdiZRNYBt.png": "Hidden RHS", | |||||
"xIE8dMQa-Ep0gPXsd5kyz.png": "I have a scooter (Have scooter)", | |||||
"Z38VvLYGL4d0zkx1zC3Mr.png": "Net zombie", | |||||
"k5s-y2Q5fQUqrbiBwHWl4.png": "Capped turkey", | |||||
"PCZZ5y3JBRNiQ2y5gsTOU.png": "Public heart", | |||||
"eBC7z-hl39_Pa8aRb7OUW.png": "Turkey fighter", | |||||
"nHUD-31QTKE8hqmoGAq-S.png": "Kind heart", | |||||
"kyzyfFRf-ojbL5wIC0TdG.png": "Humbly sit", | |||||
"e9t1WM53YtEpD2RTZC4t0.png": "Kind clothes", | |||||
"YF-DDQp1hHmkuaJ3IuhNK.png": "Drunkard holding a cross", | |||||
"pWnx-XNSF7f2CVVZ48YjR.png": "Big turkey", | |||||
"_QUoTx8EwZVpzhIM9-MKQ.png": "Cliff tofu", | |||||
"ewetW-tE3iF7Z9Rem1sXY.png": "Faithful husband", | |||||
"Foz22028Ka6i5aJcz0LMT.png": "Box of concerns" | |||||
} |
@ -0,0 +1,11 @@ | |||||
[quote="omk3, post:1, topic:56335"] | |||||
![canopy-trees|54x48](upload://uWmkV1JNTEFWBjixpQc9cVzbRmD) (canopy-trees) | |||||
[/quote] | |||||
It's worth noting that WaniKani also makes distinction between Cliff and Canopy (Dotted-cliff). | |||||
[details=though, there are parts where WaniKani doesn't make distinctions] | |||||
- Pelican (礻) or dotted pelican (衤) | |||||
- This can also be extended as far as, the other form of 礻 - [<span lang="ja-JP">祓</span>](https://moji.tekkai.com/zoom/%E7%A5%93/page.html). | |||||
- Winter (夂) or folding chair (攵) | |||||
[/details] |
@ -0,0 +1,132 @@ | |||||
import path from 'path' | |||||
import axios from 'axios' | |||||
import fs from 'fs/promises' | |||||
import { nanoid } from 'nanoid' | |||||
const ROOTDIR = 'docs/assets' | |||||
const log = { | |||||
data: {} as Record<string, string>, | |||||
filename: path.join(ROOTDIR, 'download-radical.json'), | |||||
async load() { | |||||
this.data = JSON.parse(await fs.readFile(this.filename, 'utf-8')) | |||||
return this.data | |||||
}, | |||||
async dump() { | |||||
await fs.writeFile(this.filename, JSON.stringify(this.data, null, 2)) | |||||
} | |||||
} | |||||
async function doDownloadRadical(url: string, note?: string) { | |||||
const r = await axios.get(url, { | |||||
responseType: 'arraybuffer' | |||||
}) | |||||
const filename = `${nanoid()}.png` | |||||
await fs.writeFile(path.join(ROOTDIR, filename), r.data) | |||||
console.info(filename) | |||||
if (note) { | |||||
log.data[filename] = note | |||||
} | |||||
} | |||||
async function downloadFromList(toBeDownloaded: Record<string, string>) { | |||||
const chunkSize = 50 | |||||
const entries = Object.entries(toBeDownloaded) | |||||
for (let i = 0; i < entries.length; i += chunkSize) { | |||||
await Promise.all( | |||||
entries.slice(i, i + chunkSize).map(([k, v]) => doDownloadRadical(k, v)) | |||||
) | |||||
} | |||||
} | |||||
async function main() { | |||||
await log.load() | |||||
const [, , url, ...parts] = process.argv | |||||
if (url) { | |||||
await doDownloadRadical(url, parts.join(' ')) | |||||
} else { | |||||
await downloadFromList({ | |||||
'https://git.polv.cc/attachments/d76f268a-8b40-4bba-ab24-e10de2e69f78': | |||||
'Triple power', | |||||
'https://git.polv.cc/attachments/b1a8a586-2e40-4e4f-84c5-908f93ee3215': | |||||
'Sun over spikes', | |||||
'https://git.polv.cc/attachments/6ae5fcf7-f32c-4646-9df2-a10940dd6c3d': | |||||
'Devil hat', | |||||
'https://git.polv.cc/attachments/8fed947e-a6bb-4dad-9498-22c00fdb0f93': | |||||
'Standing tree', | |||||
'https://git.polv.cc/attachments/363c907d-2bf6-4d14-9594-96ef28e222da': | |||||
'Windblown hat', | |||||
'https://git.polv.cc/attachments/cc279d52-ea36-4e6b-8812-1d0b3e469b2a': | |||||
'Horns on heaven', | |||||
'https://git.polv.cc/attachments/09a70b26-632f-4bcf-be56-0fbcc0789e7d': | |||||
'Pi tree', | |||||
'https://git.polv.cc/attachments/074e05c3-f650-4408-b0b6-12bfa298160a': | |||||
'Samurai jackhammer', | |||||
'https://git.polv.cc/attachments/7c29b116-61ca-4f2b-a12d-dc306bc83850': | |||||
'Flow', | |||||
'https://git.polv.cc/attachments/6053edc6-b463-427d-a9fc-76615eb2a4fd': | |||||
'World tree', | |||||
'https://git.polv.cc/attachments/18aa7bd9-dc8b-40d3-bd13-c904e0881cb0': | |||||
'Horned lantern', | |||||
'https://git.polv.cc/attachments/ce8db2a5-cb90-4b1f-bdb0-0b42da1b0469': | |||||
'Wolverine on the stool', | |||||
'https://git.polv.cc/attachments/3db9d7a3-9eef-446f-acfc-c2aae1134727': | |||||
'Rice on the lion', | |||||
'https://git.polv.cc/attachments/7f596256-f42d-41d7-b4c9-aedc15aa5bc7': | |||||
'Low ground', | |||||
'https://git.polv.cc/attachments/071b4b60-6897-4771-a86b-be8d4e9d96d3': | |||||
'Narrow RHS', | |||||
'https://git.polv.cc/attachments/cfe2660b-efaa-4143-ae9d-3f2fc522203c': | |||||
'Stamping stool', | |||||
'https://git.polv.cc/attachments/a11cd744-d33f-463e-91cb-41541bf4bfa2': | |||||
'Broken center', | |||||
'https://git.polv.cc/attachments/635c24de-8f6a-4ea6-8e16-9d0fc26e7cc9': | |||||
'Hooked arrow', | |||||
'https://git.polv.cc/attachments/63e354bd-81c2-404b-acd6-8a7e487f5fbc': | |||||
'Suitable flowery crown', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/5/1/3/513b03662967f3fce60e4ae9a88e5d85b374d570.png': | |||||
'Faithful husband', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/8/2/9/82965f62025a69b1f452565ad90c63255299f499.png': | |||||
'Hidden RHS', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/e/9/6/e960228e957eb9129bc8620872a6eed53a8fed17.png': | |||||
'Capped turkey', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/8/f/c/8fc229f0a11051c0d331b71bb2a3d5bb99e6d473.png': | |||||
'Turkey fighter', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/f/c/7/fc7c4eb641af0b03db3afe872d52fbc7919426d3.png': | |||||
'Big turkey', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/3/8/c/38cb1f4372909a79b1d49732b1e2ba2c8ba1b9c9.png': | |||||
'Net zombie', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/5/0/b/50b009671190170a3e84b672b0c57ce045086f09.png': | |||||
'Box of concerns', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/e/5/b/e5bdb4f2eeea49e0d10cbc56df75594356e26896.png': | |||||
'Public heart', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/6/6/2/6621b09b43e3f33fbc2da81789382b607a3d6c05.png': | |||||
'Cliff tofu', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/8/6/3/8639d863d68df6bdf1a5828b756e0cabf09e1448.png': | |||||
'Humbly sit', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/4/6/8/46839026174236dbc5f8e30c621869bc68201c9a.png': | |||||
'Drunkard holding a cross', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/f/6/e/f6e5319a1b59db79c988c4e14a13615fc233f56a.png': | |||||
'Servant stool', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/4/a/1/4a1d42926ca4097d7c63475b66481f1a4e895104.png': | |||||
'Kind heart', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/d/a/a/daab655771ae2e99de8bae1d6b1f4d6c721bc861.png': | |||||
'Kind clothes', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/4/3/9/43978d49ccdc893a5ddd768790a9a84e0ad8c965.png': | |||||
'Safety roof', | |||||
'https://aws1.discourse-cdn.com/wanikanicommunity/original/4X/d/2/d/d2d27d66900c320ad70ee40a0985ee355a757f1e.png': | |||||
'I have a scooter (Have scooter)' | |||||
}) | |||||
} | |||||
await log.dump() | |||||
} | |||||
if (require.main === module) { | |||||
main() | |||||
} |