85 lines
2.2 KiB
JavaScript
Executable File
85 lines
2.2 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
import { AudioContext } from 'web-audio-api'
|
|
import commandLineArgs from 'command-line-args'
|
|
import fetch from 'node-fetch'
|
|
|
|
const optionDefinitions = [
|
|
{ name: 'lang', type: String },
|
|
{ name: 'query', type: String },
|
|
{ name: 'stdin', type: Boolean }
|
|
]
|
|
|
|
const options = commandLineArgs(optionDefinitions)
|
|
|
|
if (options.stdin) {
|
|
handlePipedContent(data => {
|
|
options.query = data
|
|
const queries = splitString(options.query)
|
|
getAudio(options.lang, queries).then(audio => {
|
|
play(audio)
|
|
})
|
|
})
|
|
} else if (typeof options.query !== 'undefined') {
|
|
const queries = splitString(options.query)
|
|
getAudio(options.lang, queries).then(audio => {
|
|
play(audio)
|
|
})
|
|
} else {
|
|
console.log(
|
|
'At least one of the options --query or --stdin must be specified.'
|
|
)
|
|
process.exit(1)
|
|
}
|
|
|
|
function handlePipedContent (cb) {
|
|
let data = ''
|
|
|
|
process.stdin.on('readable', () => {
|
|
const chuck = process.stdin.read()
|
|
if (chuck !== null) {
|
|
data += chuck
|
|
}
|
|
})
|
|
|
|
process.stdin.on('end', () => cb(data))
|
|
}
|
|
|
|
function getAudio (lang, queries) {
|
|
const fetches = queries.map(query => {
|
|
return fetch(
|
|
'https://translate.yanknil.com/api/v1/audio/' +
|
|
lang +
|
|
'/' +
|
|
encodeURIComponent(query)
|
|
).then(res => res.json())
|
|
})
|
|
|
|
return Promise.all(fetches).then(results => {
|
|
return results.flatMap(result => result.audio)
|
|
})
|
|
}
|
|
|
|
function play (audio) {
|
|
const context = new AudioContext()
|
|
context.sampleRate = 24000
|
|
context.outStream = process.stdout
|
|
context.decodeAudioData(new Uint8Array(audio).buffer, audioBuffer => {
|
|
const source = context.createBufferSource()
|
|
source.connect(context.destination)
|
|
source.buffer = audioBuffer
|
|
source.start(0)
|
|
source.onended = () => {
|
|
process.exit()
|
|
}
|
|
})
|
|
}
|
|
|
|
function splitString (str = '') {
|
|
str = str.replace(/[\r\n]/g, '')
|
|
const regex = /([\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]{1,199}|\S[^\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]{1,197}\S(?= |$)|.{1,198}[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf])/gm
|
|
const chunks = str.match(regex)
|
|
|
|
return chunks
|
|
}
|