tts-narrator
Version:
Generate narration with Text-To-Speech technology
84 lines (83 loc) • 3.33 kB
JavaScript
;
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;