UNPKG

@jackdbd/eleventy-plugin-text-to-speech

Version:

Eleventy plugin that uses text-to-speech to generate audio assets for your website, then injects audio players in your HTML.

96 lines 3.4 kB
import fs from 'node:fs'; import path from 'node:path'; import { Readable } from 'node:stream'; import defDebug from 'debug'; import { z } from 'zod'; import { DEBUG_PREFIX } from '../constants.js'; import { asset_name } from '../schemas/common.js'; import { validatedDataOrThrow, validatedResult } from '../validation.js'; const debug = defDebug(`${DEBUG_PREFIX}:fs`); export const client_config = z.object({ /** * Base path where the audio asset will be written to the filesystem. * * @example * _site/assets/audio */ assetBasepath: z.string().min(1), /** * Subpath/subdomain under your control where the generated audio asset will * be publicly accessible. * * @example * Subpath: /assets/audio * * @example * Subdomain: https://audio.example.com */ hrefBase: z.string().min(1) }); export const write_config = z .object({ /** * Name of the audio asset to be written to the filesystem. */ assetName: asset_name, /** * Readable stream containing the audio data to be written to the filesystem. */ readable: z.instanceof(Readable) }) .describe('Filesystem write config'); /** * @internal */ export const write = (cfg, config) => { const { assetBasepath, hrefBase } = cfg; const result = validatedResult(config, write_config); if (result.error) { return { error: result.error }; } const { assetName, readable } = result.value; const filepath = path.join(assetBasepath, assetName); debug(`write ${filepath}`); // The 'w' flag opens the file for writing, and overwrites the file if it already exists. // The 'wx' flag opens the file for writing, but fails if the file already exists. const writable = fs.createWriteStream(filepath, { flags: 'w' }); readable.pipe(writable); return new Promise((resolve) => { writable.on('error', (error) => { debug(`writable stream errored`); // should I destroy the readable stream manually? // readable.destroy() resolve({ error }); }); writable.on('finish', () => { debug(`writable stream finished, no more data to flush to ${filepath}`); resolve({ value: { message: `asset written to ${filepath}`, href: `${hrefBase}/${assetName}` } }); }); // If `autoClose` is set to true (default behavior) on `'error'` or `'finish'` // the file descriptor will be closed automatically. writable.on('close', () => { debug(`writable stream closed, all underlying resources freed`); }); }); }; export const defClient = (config) => { const data = validatedDataOrThrow(config, client_config); const { assetBasepath, hrefBase } = data; debug(`audio assets will be written to ${assetBasepath} and hosted at ${hrefBase}`); if (!fs.existsSync(assetBasepath)) { debug(`${assetBasepath} does not exist, creating it`); fs.mkdirSync(assetBasepath, { recursive: true }); debug(`${assetBasepath} created`); } const writeWithHostingConfig = write.bind(null, { assetBasepath, hrefBase }); return { config: { assetBasepath, hrefBase }, write: writeWithHostingConfig }; }; //# sourceMappingURL=fs.js.map