#!/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 }