UNPKG

google-translate-api-x

Version:
92 lines (84 loc) 3.63 kB
'use strict'; const { DEFAULT_OPTIONS, TRANSLATE_PATH } = require('./defaults.cjs'); const { getCode } = require('./languages.cjs'); module.exports = function (input, options) { options = {...DEFAULT_OPTIONS, ...options}; // jQ1olc - is the specific id for spoken requests const rpcids = 'jQ1olc'; const queryParams = new URLSearchParams({ 'rpcids': rpcids, 'source-path': '/', 'f.sid': '', 'bl': '', 'hl': 'en-US', 'soc-app': 1, 'soc-platform': 1, 'soc-device': 1, '_reqid': Math.floor(1000 + (Math.random() * 9000)), 'rt': 'c' }); const url = TRANSLATE_PATH + options.tld + '/_/TranslateWebserverUi/data/batchexecute?' + queryParams.toString(); const requestOptions = {...options.requestOptions, ...DEFAULT_OPTIONS.requestOptions}; requestOptions.method = 'POST'; requestOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; const sourceArray = Array.isArray(input) ? input : (typeof input === 'object' ? Object.values(input) : [input]); const freq = []; for (let i = 0; i < sourceArray.length; i++) { const text = sourceArray[i].text ?? sourceArray[i]; if (text.length > 200) { return new Promise(() => { throw new Error('At least one of the inputs exceeded 200 characters, which is rejected by Google translate. You should split it into a batch input with arrays/objects.', {cause: {input: {text}}}); }); } const forceTo = sourceArray[i].forceTo ?? options.forceTo; const to = sourceArray[i].to ?? options.to; const toIso = forceTo ? to : getCode(to); if (toIso === null) { return new Promise(() => { throw new Error(`To language ${to} unsupported, bypass this with setting forceTo to true if you're certain the iso is correct`, {cause: {options: {to}}}); }); } // i (converted to base 36 to minimize request length) is used as a unique indentifier to order responses const freqPart = [rpcids, JSON.stringify([text, toIso, true]), null, i.toString(36)]; freq.push(freqPart); } requestOptions.body = 'f.req=' + encodeURIComponent(JSON.stringify([freq])) + '&'; return options.requestFunction(url, requestOptions).then( async res => { if (!res.ok) { throw new Error(res.statusText, {cause: {options, url, response: res}}); } res = await res.text(); res = res.slice(6); let finalResult = Array.isArray(input) ? [] : (typeof input === 'object' ? {} : undefined); for (let chunk of res.split('\n')) { if (chunk[0] !== '[' || chunk[3] === 'e') { continue; } chunk = JSON.parse(chunk); for (let translation of chunk) { if (translation[0] !== 'wrb.fr') { continue; } const id = parseInt(translation[translation.length - 1], 36); if (translation[2] === null && options.rejectOnPartialFail) { throw new Error( 'Partial TTS Request Fail: at least one TTS request failed, it was either invalid or more likely- rejected by the server. ' + 'You can try the request again and if it persists try a proxy, spacing out requests, and/or using a different tld. ' + 'If you would like to still speak other requests in a batch speak request even if one fails(the failed TTS will be ' + 'set to `null`) pass the option `rejectOnPartialFail: false`', {cause: {input, url, options, requestOptions}} ); } const result = (translation[2] !== null) ? JSON.parse(translation[2])[0] : null; if (Array.isArray(input)) { finalResult[id] = result; } else if (typeof input === 'object') { finalResult[Object.keys(input)[id]] = result; } else { finalResult = result; } } } return finalResult; }); };