UNPKG

tts-narrator

Version:

Generate narration with Text-To-Speech technology

84 lines (83 loc) 3.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getAudioFileDuration = exports.playMp3File = void 0; const tslib_1 = require("tslib"); const promise_utils_1 = require("@handy-common-utils/promise-utils"); const AV = tslib_1.__importStar(require("av")); require("mp3"); const promises_1 = tslib_1.__importDefault(require("node:fs/promises")); const stream = tslib_1.__importStar(require("node:stream")); function toBuffer(arr) { return ArrayBuffer.isView(arr) ? // To avoid a copy, use the typed array's underlying ArrayBuffer to back // new Buffer, respecting the "view", i.e. byteOffset and byteLength Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength) : // Pass through all other types to `Buffer.from` Buffer.from(arr); } // loaded class / undefined as not initialised / null as failed to load let _speakerClass; function getSpeakerClass(errorLogger) { if (_speakerClass === undefined) { try { // eslint-disable-next-line unicorn/prefer-module _speakerClass = require('speaker'); } catch (error) { _speakerClass = null; errorLogger(`Library for playing MP3 is not available: ${error}`); } } return _speakerClass; } async function playMp3File(filePath, infoLogger) { const Speaker = getSpeakerClass(infoLogger); if (!Speaker) { infoLogger(`Skipped playing MP3 because underlying library is not available: ${filePath}`); return; } const fileContent = await promises_1.default.readFile(filePath); return new Promise((resolve, reject) => { try { // eslint-disable-next-line import/namespace const asset = AV.Asset.fromBuffer(fileContent); asset.decodeToBuffer(buffer => { // Initiate the source const bufferStream = new stream.PassThrough(); // Write your buffer bufferStream.end(toBuffer(buffer)); // Pipe it to something else (i.e. stdout) const speaker = new Speaker({ channels: 1, bitDepth: 32, sampleRate: 16000, float: true, }); // as Speaker.Options); bufferStream.pipe(speaker); speaker.on('error', (error) => reject(error)); // speaker.on('end', () => { console.log('piped'); resolve(); }); speaker.on('close', () => resolve()); }); } catch (error) { reject(error); } }); } exports.playMp3File = playMp3File; async function getAudioFileDuration(filePath) { const fileContent = await promises_1.default.readFile(filePath); // eslint-disable-next-line import/namespace const asset = AV.Asset.fromBuffer(fileContent); return (0, promise_utils_1.timeoutReject)(new Promise((resolve, reject) => { try { asset.get('duration', duration => { resolve(duration); }); } catch (error) { reject(error); } }), 20000, new Error(`Unable to determine audio duration, is the file '${filePath}' corrupted?`)); } exports.getAudioFileDuration = getAudioFileDuration;