Skip to content
This repository was archived by the owner on Apr 13, 2025. It is now read-only.

feat: Add opentts service and sample #749

Merged
merged 2 commits into from
Sep 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ nodecg-io is the successor of [ChatOverflow](https://github.com/codeoverflow-org
- MQTT
- Nanoleafs
- OBS
- [OpenTTS](https://github.com/synesthesiam/opentts)
- Philips Hue
- RCON
- Reddit
Expand Down
102 changes: 100 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions samples/opentts/extension/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { NodeCG } from "nodecg-types/types/server";
import { OpenTTSClient } from "nodecg-io-opentts";
import { requireService } from "nodecg-io-core";

/**
* Plays a "hello world" tts message inside the graphic of this sample bundle.
*/
async function playTTSInGraphic(client: OpenTTSClient, nodecg: NodeCG) {
const voices = await client.getVoices("en");

// Get random voice
const voiceName = Object.keys(voices)[Math.floor(Math.random() * Object.keys(voices).length)];
if (voiceName === undefined) throw new Error("no voice available");

const helloWorldUrl = client.generateWavUrl("Hello World", voiceName);
await nodecg.sendMessage("setSrc", helloWorldUrl);
}

module.exports = function (nodecg: NodeCG) {
nodecg.log.info("Sample bundle for the OpenTTS service started.");

const opentts = requireService<OpenTTSClient>(nodecg, "opentts");

nodecg.listenFor("ready", () => {
const client = opentts?.getClient();
if (client !== undefined){
playTTSInGraphic(client, nodecg)
.catch(err => nodecg.log.error(`Error while trying to play tts message: ${err.messages}`));
}
});

opentts?.onAvailable(async (client) => {
nodecg.log.info("OpenTTS service available.");

const voices = await client.getVoices();
const languages = await client.getLanguages();

nodecg.log.info(
`OpenTTS server supports ${Object.entries(voices).length} voices in ${languages.length} languages.`,
);

await playTTSInGraphic(client, nodecg);
});

opentts?.onUnavailable(() => {
nodecg.log.info("OpenTTS service unavailable.");
});
};
10 changes: 10 additions & 0 deletions samples/opentts/graphics/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>OpenTTS Sample</title>
</head>
<body>
<audio controls id="opentts-audio"></audio>
<script src="index.js"></script>
</body>
</html>
14 changes: 14 additions & 0 deletions samples/opentts/graphics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/// <reference types="nodecg-types/types/browser" />

// Listens for event from opentts sample and plays the audio by the provided url.

const audioElement = document.getElementById("opentts-audio") as HTMLAudioElement;

// Play audio when the graphic is newly opened
nodecg.sendMessage("ready");

nodecg.listenFor("setSrc", (newSrc) => {
audioElement.src = newSrc;
audioElement.currentTime = 0;
audioElement.play();
});
27 changes: 27 additions & 0 deletions samples/opentts/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "opentts",
"version": "0.3.0",
"private": true,
"nodecg": {
"compatibleRange": "^1.1.1",
"bundleDependencies": {
"nodecg-io-template": "^0.3.0"
},
"graphics": [
{
"file": "index.html",
"width": "1920",
"height": "1080"
}
]
},
"license": "MIT",
"dependencies": {
"@types/node": "^18.7.13",
"nodecg-types": "^1.9.0",
"nodecg-io-core": "^0.3.0",
"nodecg-io-opentts": "^0.3.0",
"typescript": "^4.8.2",
"nodecg-io-tsconfig": "^1.0.0"
}
}
11 changes: 11 additions & 0 deletions samples/opentts/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "nodecg-io-tsconfig",
"references": [
{
"path": "../../nodecg-io-core"
},
{
"path": "../../services/nodecg-io-opentts"
}
]
}
32 changes: 32 additions & 0 deletions services/nodecg-io-opentts/extension/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NodeCG } from "nodecg-types/types/server";
import { Result, emptySuccess, success, ServiceBundle, Logger, error } from "nodecg-io-core";
import { OpenTTSClient } from "./openTtsClient";

export interface OpenTTSConfig {
host: string;
useHttps?: boolean;
}

export { OpenTTSClient, OpenTTSVoice } from "./openTtsClient";

module.exports = (nodecg: NodeCG) => {
new OpenTTSService(nodecg, "opentts", __dirname, "../schema.json").register();
};

class OpenTTSService extends ServiceBundle<OpenTTSConfig, OpenTTSClient> {
async validateConfig(config: OpenTTSConfig): Promise<Result<void>> {
if (await OpenTTSClient.isOpenTTSAvailable(config)) return emptySuccess();
else return error("Unable to reach OpenTTS server at the specified host address");
}

async createClient(config: OpenTTSConfig, logger: Logger): Promise<Result<OpenTTSClient>> {
const client = new OpenTTSClient(config);
logger.info("Successfully created OpenTTS client.");
return success(client);
}

stopClient(_: OpenTTSClient, logger: Logger): void {
// Client is stateless, no need to stop anything
}
}

Loading