import axios, { AxiosRequestConfig, AxiosResponse } from "axios"; import * as fs from "fs"; export const ttVoice = { en_male_jomboy: "Game On", en_us_002: "Jessie", es_mx_002: "Spanish MX - Male", en_male_funny: "Wacky", en_us_ghostface: "Ghost Face", en_female_samc: "Empathetic", en_male_cody: "Serious", en_female_makeup: "Beauty Guru", en_female_richgirl: "Bestie", en_male_grinch: "Trickster", en_us_006: "Joey", en_male_narration: "Story Teller", en_male_deadpool: "Mr. GoodGuy", en_uk_001: "Narrator", en_uk_003: "Male English UK", en_au_001: "Metro", en_male_jarvis: "Alfred", en_male_ashmagic: "ashmagic", en_male_olantekkers: "olantekkers", en_male_ukneighbor: "Lord Cringe", en_male_ukbutler: "Mr. Meticulous", en_female_shenna: "Debutante", en_female_pansino: "Varsity", en_male_trevor: "Marty", en_female_f08_twinkle: "Pop Lullaby", en_male_m03_classical: "Classic Electric", en_female_betty: "Bae", en_male_cupid: "Cupid", en_female_grandma: "Granny", en_male_m2_xhxs_m03_christmas: "Cozy", en_male_santa_narration: "Author", en_male_sing_deep_jingle: "Caroler", en_male_santa_effect: "Santa", en_female_ht_f08_newyear: "NYE 2023", en_male_wizard: "Magician", en_female_ht_f08_halloween: "Opera", en_female_ht_f08_glorious: "Glorious", en_male_sing_funny_it_goes_up: "It Goes Up", en_female_ht_f08_wonderful_world: "Dramatic", en_male_m2_xhxs_m03_silly: "Chipmunk", en_female_emotional: "Peaceful", en_male_m03_sunshine_soon: "Sunshine Soon", en_female_f08_warmy_breeze: "Warmy Breeze", en_male_m03_lobby: "Tenor", en_male_sing_funny_thanksgiving: "Thanksgiving", en_female_f08_salut_damour: "Alto", en_us_007: "Professor", en_us_009: "Scientist", en_us_010: "Confidence", en_au_002: "Smooth", en_us_chewbacca: "Chewbacca", en_us_c3po: "C3PO", en_us_stitch: "Stitch", en_us_stormtrooper: "Stormtrooper", en_us_rocket: "Rocket", en_female_madam_leota: "Madame Leota", en_male_ghosthost: "Ghost Host", en_male_pirate: "Pirate", fr_001: "French - Male 1", fr_002: "French - Male 2", es_002: "Spanish (Spain) - Male", br_001: "Portuguese BR - Female 1", br_003: "Portuguese BR - Female 2", br_004: "Portuguese BR - Female 3", br_005: "Portuguese BR - Male", bp_female_ivete: "Ivete Sangalo", bp_female_ludmilla: "Ludmilla", pt_female_lhays: "Lhays Macedo", pt_female_laizza: "Laizza", pt_male_bueno: "Galvão Bueno", de_001: "German - Female", de_002: "German - Male", id_001: "Indonesian - Female", jp_001: "Japanese - Female 1", jp_003: "Japanese - Female 2", jp_005: "apanese - Female 3", jp_006: "Japanese - Male", jp_female_fujicochan: "りーさ", jp_female_hasegawariona: "世羅鈴", jp_male_keiichinakano: "Morio’s Kitchen", jp_female_oomaeaika: "夏絵ココ", jp_male_yujinchigusa: "低音ボイス", jp_female_shirou: "四郎", jp_male_tamawakazuki: "玉川寿紀", jp_female_kaorishoji: "庄司果織", jp_female_yagishaki: "八木沙季", jp_male_hikakin: "ヒカキン", jp_female_rei: "丸山礼", jp_male_shuichiro: "修一朗", jp_male_matsudake: "マツダ家の日常", jp_female_machikoriiita: "まちこりーた", jp_male_matsuo: "モジャオ", jp_male_osada: "モリスケ", kr_002: "Korean - Male 1", kr_003: "Korean - Female", kr_004: "Korean - Male 2", BV074_streaming: "Female", BV075_streaming: "Male", }; export default class TikTokTTS { private sessionId: string | null = null; private tiktokUrl: string = "https://api16-normal-v6.tiktokv.com/media/api/text/speech/invoke"; private defaultSpeaker: string = "BV075_streaming"; constructor(sessionId: string, tiktokUrl?: string) { if (!sessionId) { throw new Error("Session notfound"); } if (tiktokUrl) { this.tiktokUrl = tiktokUrl; } } private prepareText(text:string) { text = text.replace("+", "plus"); text = text.replace(/\s/g, "+"); text = text.replace("&", "and"); return text; } private handleStatusError(status_code:number) { switch (status_code) { case 1: throw new Error(`Your TikTok session id might be invalid or expired. Try getting a new one. status_code: ${status_code}`); case 2: throw new Error(`The provided text is too long. status_code: ${status_code}`); case 4: throw new Error(`Invalid speaker, please check the list of valid speaker values. status_code: ${status_code}`); case 5: throw new Error(`No session id found. status_code: ${status_code}`); } } async tts(text: string, speech?: string, output?: string): Promise { try { let content = this.prepareText(text); speech = speech || this.defaultSpeaker; output = output || "audio"; let url = `${this.tiktokUrl}/?text_speaker=${speech}&req_text=${content}&speaker_map_type=0&aid=1233`; let config: AxiosRequestConfig = { url: url, method: "POST", headers: { "User-Agent": "com.zhiliaoapp.musically/2022600030 (Linux; U; Android 7.1.2; es_ES; SM-G988N; Build/NRD90M;tt-ok/3.12.13.1)", Cookie: `sessionid=${this.sessionId}`, "Accept-Encoding": "gzip,deflate,compress", }, }; let { data:response }: AxiosResponse = await axios(config); if(response?.status_code !== 0){ return this.handleStatusError(response.status_code) } let base64 = response.data?.v_str fs.writeFileSync(`${output}.mp3`, Buffer.from(base64, 'base64')); } catch (e) { throw e } } }