83 lines
2.2 KiB
TypeScript
83 lines
2.2 KiB
TypeScript
import fs from "node:fs";
|
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
import path from "node:path";
|
|
import type { Connect, Plugin, ViteDevServer } from "vite";
|
|
import { spawn } from "child_process";
|
|
|
|
export function gttsPlugin(): Plugin {
|
|
return {
|
|
name: "gtts",
|
|
configureServer(server: ViteDevServer) {
|
|
// Vite dev server middlewares are connect-style: (req, res, next)
|
|
server.middlewares.use(async (req, res, next) => {
|
|
const reqUrl = req.url;
|
|
if (!reqUrl) return next();
|
|
|
|
const url = new URL(reqUrl, "http://localhost");
|
|
if (url.pathname !== "/api/tts") return next();
|
|
|
|
const text = url.searchParams.get("text");
|
|
if (!text) return next();
|
|
|
|
try {
|
|
await gtts(text, req, res, next);
|
|
} catch (e) {
|
|
console.error(e, reqUrl);
|
|
next();
|
|
}
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
let fileList: Record<string, number> = {};
|
|
|
|
async function gtts(
|
|
text: string,
|
|
req: Connect.IncomingMessage,
|
|
res: ServerResponse<IncomingMessage>,
|
|
next: Connect.NextFunction,
|
|
) {
|
|
text = text.replace(/["]/g, " ");
|
|
|
|
const saveroot = ".gtts";
|
|
fs.mkdirSync(saveroot, { recursive: true });
|
|
|
|
const fileListJSON = path.join(saveroot, "gtts.json");
|
|
|
|
if (Object.keys(fileList).length === 0 && fs.existsSync(fileListJSON)) {
|
|
fileList = JSON.parse(fs.readFileSync(fileListJSON, "utf-8"));
|
|
}
|
|
|
|
const fileNo = fileList[text] || Object.keys(fileList).length;
|
|
const filename = `${fileNo}.mp3`;
|
|
const saveto = path.join(saveroot, filename);
|
|
|
|
if (!fs.existsSync(saveto)) {
|
|
await new Promise((resolve, reject) => {
|
|
const p = spawn(
|
|
"gtts-cli",
|
|
[
|
|
`"${text}"`,
|
|
...["--lang", "ko"],
|
|
...["--output", path.join(process.cwd(), saveto)],
|
|
],
|
|
{
|
|
stdio: "inherit",
|
|
shell: true,
|
|
},
|
|
);
|
|
p.on("error", reject).on("close", resolve);
|
|
});
|
|
fileList[text] = fileNo;
|
|
console.log(`gtts: ${text} saved to ${saveto}`);
|
|
|
|
fs.writeFileSync(fileListJSON, JSON.stringify(fileList, null, 2));
|
|
} else {
|
|
// console.log(`gtts: ${text} loaded from ${saveto}`);
|
|
}
|
|
|
|
res.setHeader("Content-Type", "audio/mpeg");
|
|
fs.createReadStream(saveto).pipe(res);
|
|
}
|