download all assets
This commit is contained in:
1 parent
b935bb97b9
commit
5d137dd4b5
52 files changed
+1874
-446
No files matched your search
@@ -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()
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import yaml from 'js-yaml'
|
||||
import { toKatakana } from 'wanakana'
|
||||
|
||||
import { subjects } from './dump-subjects'
|
||||
import { IKanji, IRadical } from './shared'
|
||||
|
||||
interface IItem {
|
||||
document_url: string
|
||||
level: number
|
||||
meaning: string
|
||||
reading?: string
|
||||
components: {
|
||||
[source: string]: string[]
|
||||
}
|
||||
similar: string[]
|
||||
image?: {
|
||||
src: string
|
||||
content_type: string
|
||||
width: string | undefined
|
||||
height: string | undefined
|
||||
}
|
||||
}
|
||||
|
||||
interface IBeautifiedRadicals {
|
||||
[id: string]: IItem
|
||||
}
|
||||
|
||||
export const radicals = {
|
||||
data: {} as IBeautifiedRadicals,
|
||||
filename: 'radicals.yaml',
|
||||
load() {
|
||||
this.data = yaml.load(
|
||||
fs.readFileSync(this.filename, 'utf-8')
|
||||
) as IBeautifiedRadicals
|
||||
return this.data
|
||||
},
|
||||
dump(d: IBeautifiedRadicals) {
|
||||
this.data = d
|
||||
this.finalize()
|
||||
},
|
||||
finalize() {
|
||||
fs.writeFileSync(
|
||||
this.filename,
|
||||
yaml.dump(this.data, {
|
||||
skipInvalid: true
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const rs = subjects.load()
|
||||
|
||||
const idMap = new Map<number, string>()
|
||||
radicals.data = {}
|
||||
|
||||
rs.filter((r) => r.object === 'radical').map((r0) => {
|
||||
const r = r0 as IRadical
|
||||
const d = {
|
||||
document_url: r.data.document_url,
|
||||
level: r.data.level,
|
||||
meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning,
|
||||
components: {},
|
||||
sup: r.data.amalgamation_subject_ids.map((it) => it.toString()),
|
||||
similar: []
|
||||
}
|
||||
|
||||
let id = r.data.characters
|
||||
|
||||
if (id) {
|
||||
radicals.data[id] = d
|
||||
} else {
|
||||
id = d.meaning
|
||||
|
||||
const st = (im: {
|
||||
content_type: string
|
||||
metadata: { dimensions?: string }
|
||||
}) =>
|
||||
im.content_type === 'image/svg+xml'
|
||||
? 5000
|
||||
: im.metadata.dimensions
|
||||
? Math.min(...im.metadata.dimensions.split('x').map(Number))
|
||||
: 0
|
||||
const im = r.data.character_images.sort((a, b) => st(a) - st(b))[0]!
|
||||
const dim = im.metadata.dimensions?.split('x') || []
|
||||
|
||||
radicals.data[id] = {
|
||||
...d,
|
||||
image: {
|
||||
src: im.url,
|
||||
content_type: im.content_type,
|
||||
width: dim[0],
|
||||
height: dim[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idMap.set(r.id, id)
|
||||
})
|
||||
|
||||
rs.filter((r) => r.object === 'kanji').map((r0) => {
|
||||
const r = r0 as IKanji
|
||||
const reading = r.data.readings.filter((m) => m.primary)[0]!
|
||||
const d = {
|
||||
document_url: r.data.document_url,
|
||||
level: r.data.level,
|
||||
meaning: r.data.meanings.filter((m) => m.primary)[0]!.meaning,
|
||||
reading:
|
||||
reading.type === 'onyomi'
|
||||
? toKatakana(reading.reading)
|
||||
: reading.reading,
|
||||
components: {
|
||||
wanikani: r.data.component_subject_ids.map((it) => it.toString())
|
||||
},
|
||||
similar: r.data.visually_similar_subject_ids.map((it) => it.toString())
|
||||
}
|
||||
|
||||
const id = r.data.characters
|
||||
idMap.set(r.id, id)
|
||||
// const prev = radicals.data[id]
|
||||
|
||||
// if (prev) {
|
||||
// radicals.data[id] = {
|
||||
// ...d,
|
||||
// sup: prev.sup
|
||||
// }
|
||||
// } else {
|
||||
// radicals.data[id] = {
|
||||
// ...d,
|
||||
// sup: []
|
||||
// }
|
||||
// }
|
||||
|
||||
radicals.data[id] = d
|
||||
})
|
||||
|
||||
for (const [k, v] of Object.entries(radicals.data)) {
|
||||
if (v.components?.['wanikani']) {
|
||||
v.components['wanikani'] = v.components['wanikani']
|
||||
.map((s) => idMap.get(Number(s)) || s)
|
||||
.filter((s) => s !== k)
|
||||
}
|
||||
v.similar = v.similar.map((s) => idMap.get(Number(s)) || s)
|
||||
// v.sup = v.sup.map((s) => idMap.get(Number(s)) || s)
|
||||
}
|
||||
|
||||
radicals.finalize()
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import { radicals } from './beautify-radicals'
|
||||
|
||||
async function main() {
|
||||
const map = radicals.load()
|
||||
|
||||
fs.writeFileSync(
|
||||
'../../_radicals.md',
|
||||
Object.entries(map)
|
||||
.map(([k, v]) => {
|
||||
const headers = [k]
|
||||
if (v.meaning !== k) {
|
||||
headers.push(v.meaning)
|
||||
}
|
||||
if (v.reading) {
|
||||
headers.push(v.reading)
|
||||
}
|
||||
headers.push(String(v.level))
|
||||
|
||||
const rows = [`## ${headers.join(', ')}`, '']
|
||||
if (v.image) {
|
||||
rows.push(
|
||||
`<img src="${v.image.src}" alt="${k}"${
|
||||
v.image.width ? ` width="${v.image.width}"` : ''
|
||||
}${v.image.height ? ` height="${v.image.height}"` : ''} />`,
|
||||
''
|
||||
)
|
||||
}
|
||||
|
||||
return rows.join('\n')
|
||||
})
|
||||
.join('\n\n')
|
||||
)
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
import fs from 'fs'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import { IKanji, IRadical } from './shared'
|
||||
|
||||
export const subjects = {
|
||||
data: [] as (IKanji | IRadical)[],
|
||||
filename: 'wanikani.json',
|
||||
load() {
|
||||
this.data = JSON.parse(fs.readFileSync(this.filename, 'utf-8'))
|
||||
return this.data
|
||||
},
|
||||
dump(d: (IKanji | IRadical)[]) {
|
||||
this.data = d
|
||||
this.finalize()
|
||||
},
|
||||
finalize() {
|
||||
fs.writeFileSync(this.filename, JSON.stringify(this.data))
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const wk = axios.create({
|
||||
baseURL: 'https://api.wanikani.com/v2/',
|
||||
headers: {
|
||||
Authorization: `Bearer ${process.env['WANIKANI_API_KEY']}`
|
||||
}
|
||||
})
|
||||
|
||||
const data: (IKanji | IRadical)[] = []
|
||||
|
||||
let nextURL = '/subjects?types=radical,kanji'
|
||||
while (nextURL) {
|
||||
const r = await wk
|
||||
.get<{
|
||||
pages: {
|
||||
next_url?: string
|
||||
}
|
||||
data: (IKanji | IRadical)[]
|
||||
}>(nextURL)
|
||||
.then((r) => r.data)
|
||||
data.push(...r.data)
|
||||
console.info(r.pages.next_url)
|
||||
nextURL = r.pages.next_url || ''
|
||||
}
|
||||
|
||||
subjects.dump(data)
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main()
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
export interface IKanji {
|
||||
id: number
|
||||
/** Actual type */
|
||||
object: 'kanji'
|
||||
url: string
|
||||
data_updated_at: string
|
||||
data: {
|
||||
level: number
|
||||
document_url: string
|
||||
characters: string
|
||||
meanings: {
|
||||
meaning: string
|
||||
primary: boolean
|
||||
}[]
|
||||
readings: {
|
||||
reading: string
|
||||
primary: boolean
|
||||
type: 'kunyomi' | 'onyomi'
|
||||
}[]
|
||||
component_subject_ids: number[]
|
||||
visually_similar_subject_ids: number[]
|
||||
}
|
||||
}
|
||||
|
||||
export interface IRadical {
|
||||
id: number
|
||||
/** Actual type */
|
||||
object: 'radical'
|
||||
url: string
|
||||
data_updated_at: string
|
||||
data: {
|
||||
level: number
|
||||
document_url: string
|
||||
characters: string | null
|
||||
character_images: {
|
||||
url: string
|
||||
metadata: {
|
||||
inline_styles?: boolean
|
||||
dimensions?: string
|
||||
}
|
||||
content_type: string
|
||||
}[]
|
||||
meanings: {
|
||||
meaning: string
|
||||
primary: boolean
|
||||
}[]
|
||||
amalgamation_subject_ids: number[]
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user