TGViewer
Артем Лещев | ИТ Артем Лещев | ИТ @asleshchev · 70 subscribers
Post #141 94
На работе была проблема: сессия быстро протухала в Text-To-Speech-сервисе. Частые залогины меня бесили и я написал js-скрипт для выполнения из консоли браузера. Сейчас нарушается принцип DRY: у меня дважды прописан процесс создания аудиофайла, но... пока так.
Порефакторю потом.

✔️ HTTP-запросы отправляются методом fetch(). Он всегда работает асинхронно, поэтому взял синтаксис async/await. И хотя запросы не блокируются во время ожидания ответа от сервера, процесс все равно синхронен.

✔️ Аудиофайл создается так:

1️⃣ Fetch всегда отдает данные как promise. Приводим промис к json и забираем base64-строку.

Ukfj/9//0P...

2️⃣ Функцией atob() декодируем её в бинарную строку. В ней каждый символ будет представлять байт бинарных данных.

Кракозябры. Не сойдется кодировка, но это не важно.

3️⃣ Мы все ещё работаем со строкой. Для создания аудиофайла нужны байты. Приведём строку к структуре массива байтов Uint8Array. Наша цель получить кол-во элементов в массиве равное длине бинарной строки.

Много нулей:
0, 0, 0...
Нам важно только чтобы кол-во элементов массива равнялось их кол-ву в бинарной строке!

Тип данных уже не string, а object!

4️⃣ Проходим циклом по массиву байтов, меняя каждый 0 на char-код каждого символа строки.

Нули заменены на char-коды символов: 82, 73, 70, 70...

5️⃣ Создаем объект Blob, представляющий сырые бинарные данные (коллекция байтов). На вход подаётся созданный ранее массив. Со строками он не умеет работать, отсюда и вся махинация.

6️⃣ Создаем url нашего файла, а затем и сам аудиофайл через объект new Audio(url);

7️⃣ Запускаем озвучку в браузере методом .play().

✔️ Бинго! Надо озвучить другой текст? Подставляем его в тело запроса и жмем Enter.

const getAudio = async() => {
try {
sessionIdFromLs = localStorage.getItem("session_id");
const response1 = await fetch("ЗАПРОС НА TTS-СИНТЕЗ", {
"headers": {
"X-Session-ID": `${sessionIdFromLs}`,
"Content-Type": "application/json"
},\
"body": "{ТЕКСТ ДЛЯ ОЗВУЧКИ}",
"method": "POST"
});
if (response1.ok) {
const data_blob = await response1.json();
const blob_value = data_blob.data;
const binary = atob(blob_value);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i <binary.length; i++) bytes[i] = binary.charCodeAt(i);
const blob = new Blob([bytes], {type: 'audio/wav'});
const url = URL.createObjectURL(blob);
const audio = new Audio(url);
audio.play()
} else {
const response2 = await fetch("ЗАПРОС СОЗДАНИЯ СЕССИИ", {
"headers": {
"content-type": "application/json"
},
"body": "{ЛОГИН И ПАРОЛЬ}",
"method": "POST"
});
const data = await response2.json();
sessionIdFromLs = data.session_id;
localStorage.setItem("session_id", sessionIdFromLs);
const response3 = await fetch("ЗАПРОС НА TTS-СИНТЕЗ", {
"headers": {
"X-Session-ID": `${sessionIdFromLs}`,
"Content-Type": "application/json"
},
"body": "{ТЕКСТ ДЛЯ ОЗВУЧКИ}",
"method": "POST"
});
const data_blob = await response3.json();
const blob_value = data_blob.data;
const binary = atob(blob_value);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i <binary.length; i++) bytes[i] = binary.charCodeAt(i);
const blob = new Blob([bytes], {type: 'audio/wav'});
const url = URL.createObjectURL(blob);
const audio = new Audio(url);
audio.play()
};
} catch(error) {
console.error('Ошибка: ', error);
};
};

getAudio()
MDN Web Docs Введение в асинхронный JavaScript - Изучение веб-разработки | MDN В этой статье мы кратко остановимся на проблемах, связанных с синхронным Javascript, а также ознакомимся с несколькими асинхронными методами, демонстрирующими как они могут помочь нам подобные проблемы решить.
  • 🔥 1
More from @asleshchev
  1. Aug 31, 2026Post #146
  2. Aug 9, 2026🛡 XSS-атака и аспекты безопасного API. Когда я 3-4 года назад работал менеджером ИТ-проек…
  3. Aug 1, 2026Есть у меня пара знакомых программистов, которые работают с железом. На мой вопрос — кто и…
  4. Jul 26, 2026🛡 CSRF-атака и аспекты безопасного API. CSRF произносится как sea-surf. Cross-Site Reques…
  5. Jul 17, 2026Post #142
  6. Jun 27, 2026🏖️ Однажды я обращался на горячую линию к одному тур-оператору. Меня встретил голосовой п…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →