All files getAudioBase64.ts

100% Statements 58/58
96.96% Branches 32/33
100% Functions 3/3
100% Lines 41/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 1333x 3x 3x                                       3x   34x   34x   24x 2x     22x 2x         20x                               17x 17x   1x       16x 3x       13x 13x   1x     12x                                                 3x   21x 21x 21x 21x 21x 21x     21x   11x 1x     10x 2x     8x 8x 10x       6x 6x 8x 8x 8x     6x    
import assertInputTypes from './assertInputTypes';
import axios from 'axios';
import splitLongText from './splitLongText';
 
interface Option {
  lang?: string;
  slow?: boolean;
  host?: string;
  timeout?: number;
}
 
/**
 * Get "Google TTS" audio base64 text
 *
 * @param {string}   text           length should be less than 200 characters
 * @param {object?}  option
 * @param {string?}  option.lang    default is "en"
 * @param {boolean?} option.slow    default is false
 * @param {string?}  option.host    default is "https://translate.google.com"
 * @param {number?}  option.timeout default is 10000 (ms)
 * @returns {Promise<string>} url
 */
export const getAudioBase64 = async (
    text: string,
    { lang = 'en', slow = false, host = 'https://translate.google.com', timeout = 10000 }: Option = {}
): Promise<string> => {
  assertInputTypes(text, lang, slow, host);
 
  if (typeof timeout !== 'number' || timeout <= 0) {
    throw new TypeError('timeout should be a positive number');
  }
 
  if (text.length > 200) {
    throw new RangeError(
        `text length (${text.length}) should be less than 200 characters. Try "getAllAudioBase64(text, [option])" for long text.`
    );
  }
 
  const res = await axios({
    method: 'post',
    baseURL: host,
    url: '/_/TranslateWebserverUi/data/batchexecute',
    timeout,
    data:
        'f.req=' +
        encodeURIComponent(
            JSON.stringify([
              [['jQ1olc', JSON.stringify([text, lang, slow ? true : null, 'null']), null, 'generic']],
            ])
        ),
  });
 
  // 1. parse audio base64 string
  let result;
  try {
    result = eval(res.data.slice(5))[0][2];
  } catch (e) {
    throw new Error(`parse response failed:\n${res.data}`);
  }
 
  // Check the result. The result will be null if given the lang doesn't exist
  if (!result) {
    throw new Error(`lang "${lang}" might not exist`);
  }
 
  // 2. continue to parse audio base64 string
  try {
    result = eval(result)[0];
  } catch (e) {
    throw new Error(`parse response failed:\n${res.data}`);
  }
 
  return result;
};
 
interface LongTextOption extends Option {
  splitPunct?: string;
}
 
/**
 * @typedef {object} Result
 * @property {string} shortText
 * @property {string} base64
 */
 
/**
 * Split the long text into multiple short text and generate audio base64 list
 *
 * @param {string}   text
 * @param {object?}  option
 * @param {string?}  option.lang        default is "en"
 * @param {boolean?} option.slow        default is false
 * @param {string?}  option.host        default is "https://translate.google.com"
 * @param {string?}  option.splitPunct  split punctuation
 * @param {number?}  option.timeout     default is 10000 (ms)
 * @return {Result[]} the list with short text and audio base64
 */
export const getAllAudioBase64 = async (
    text: string,
    {
      lang = 'en',
      slow = false,
      host = 'https://translate.google.com',
      splitPunct = '',
      timeout = 10000,
    }: LongTextOption = {}
): Promise<{ shortText: string; base64: string }[]> => {
  assertInputTypes(text, lang, slow, host);
 
  if (typeof splitPunct !== 'string') {
    throw new TypeError('splitPunct should be a string');
  }
 
  if (typeof timeout !== 'number' || timeout <= 0) {
    throw new TypeError('timeout should be a positive number');
  }
 
  const shortTextList = splitLongText(text, { splitPunct });
  const base64List = await Promise.all(
      shortTextList.map((shortText) => getAudioBase64(shortText, { lang, slow, host, timeout }))
  );
 
  // put short text and base64 text in a list
  const result: { shortText: string; base64: string }[] = [];
  for (let i = 0; i < shortTextList.length; i++) {
    const shortText = shortTextList[i];
    const base64 = base64List[i];
    result.push({ shortText, base64 });
  }
 
  return result;
};