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

Commit 8899bc2

Browse files
authored
Add replicant with last events to streamelement service (#494)
* Add replicant with last events to streamelement service * Fix lintern warning due to empty object in se-events graphic * Fix vue import in streamelements-events * Fix lockfile * Remove streamelements sample vue path alias * Address review comments
1 parent 23e3eff commit 8899bc2

File tree

12 files changed

+2116
-5137
lines changed

12 files changed

+2116
-5137
lines changed

package-lock.json

Lines changed: 1867 additions & 5124 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

samples/streamelements-events/extension/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { NodeCG } from "nodecg-types/types/server";
2-
import { StreamElementsServiceClient } from "nodecg-io-streamelements";
2+
import { StreamElementsReplicant, StreamElementsServiceClient } from "nodecg-io-streamelements";
33
import { requireService } from "nodecg-io-core";
44

55
module.exports = function (nodecg: NodeCG) {
66
nodecg.log.info("Sample bundle for StreamElements started");
77

88
const streamElements = requireService<StreamElementsServiceClient>(nodecg, "streamelements");
9+
const streamElementsReplicant = nodecg.Replicant<StreamElementsReplicant>("streamelements");
910

1011
streamElements?.onAvailable((client) => {
1112
nodecg.log.info("SE client has been updated, registering handlers now.");
@@ -30,6 +31,10 @@ module.exports = function (nodecg: NodeCG) {
3031

3132
client.onGift((data) => {
3233
if (data.data.tier) {
34+
// We want to display the tier as 1, 2, 3
35+
// However StreamElements stores the sub tiers as 1000, 2000 and 3000.
36+
// So we divide the tier by 1000 to get the tier in our expected format.
37+
// We don't need to care about prime subs here because they cannot be gifted.
3338
const tier = (Number.parseInt(data.data.tier) / 1000).toString();
3439
if (data.data.sender) {
3540
nodecg.log.info(
@@ -62,6 +67,8 @@ module.exports = function (nodecg: NodeCG) {
6267
client.onTest((data) => {
6368
nodecg.log.info(JSON.stringify(data));
6469
});
70+
71+
client.setupReplicant(streamElementsReplicant);
6572
});
6673

6774
streamElements?.onUnavailable(() => nodecg.log.info("SE client has been unset."));
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"extends": "nodecg-io-tsconfig",
3+
"references": [
4+
{
5+
"path": "../../../nodecg-io-core"
6+
},
7+
{
8+
"path": "../../../services/nodecg-io-streamelements"
9+
}
10+
]
11+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// @ts-check
2+
/* eslint-disable @typescript-eslint/no-var-requires */
3+
/* eslint-disable no-undef */
4+
/* eslint-disable no-console */
5+
6+
const esbuild = require("esbuild");
7+
const esbuildAlias = require("esbuild-plugin-alias");
8+
const path = require("path");
9+
const process = require("process");
10+
const fs = require("fs");
11+
12+
const args = new Set(process.argv.slice(2));
13+
const prod = process.env.NODE_ENV === "production";
14+
15+
if (args.has("--clean") || args.has("--rebuild")) {
16+
// Remove dist folder
17+
try {
18+
fs.rmSync(path.join(__dirname, "index.js"));
19+
} catch (error) {
20+
console.log(error);
21+
}
22+
23+
if (!args.has("--rebuild")) {
24+
process.exit(0);
25+
}
26+
}
27+
28+
/** @type {import('esbuild').BuildOptions} */
29+
const BuildOptions = {
30+
bundle: true,
31+
entryPoints: [path.join(__dirname, "index.ts")],
32+
minify: prod,
33+
outfile: path.join(__dirname, "index.js"),
34+
platform: "browser",
35+
sourcemap: true,
36+
watch: args.has("--watch"),
37+
plugins: [
38+
esbuildAlias({
39+
"vue": require.resolve("vue/dist/vue.esm-bundler.js"),
40+
})
41+
]
42+
};
43+
44+
esbuild
45+
.build(BuildOptions)
46+
.catch(() => process.exit(1))
47+
.then((result) => {
48+
if (result.errors.length > 0) {
49+
console.error(result.errors);
50+
}
51+
52+
if (result.warnings.length > 0) {
53+
console.error(result.warnings);
54+
}
55+
});
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charstreamElementsReplicantt="UTF-8" />
5+
<title>streamelements-events sample bundle</title>
6+
<style>
7+
body {
8+
font-family: sans-streamElementsReplicantrif;
9+
}
10+
/* don't show container until vue has compiled all templates */
11+
[v-cloak] {
12+
display: none;
13+
}
14+
</style>
15+
</head>
16+
17+
<body>
18+
<h1>streamelements-events sample bundle</h1>
19+
<div id="app" v-cloak>
20+
<p>Newest events of configured streamelements instance:</p>
21+
<p>
22+
Last subscriber:
23+
<span v-if="streamElementsReplicant?.lastSubscriber">
24+
{{ streamElementsReplicant?.lastSubscriber?.data.displayName }} subscribed for {{
25+
streamElementsReplicant?.lastSubscriber?.data.amount }} months ({{ subTier }}).
26+
</span>
27+
<span v-else>none</span>
28+
</p>
29+
<p>
30+
Last tip:
31+
<span v-if="streamElementsReplicant?.lastTip">
32+
{{ streamElementsReplicant?.lastSubscriber?.data.displayName }} subscribed for {{
33+
streamElementsReplicant?.lastSubscriber?.data.amount }} months.
34+
</span>
35+
<span v-else>none</span>
36+
</p>
37+
<p>
38+
Last cheer:
39+
<span v-if="streamElementsReplicant?.lastCheer">
40+
{{ streamElementsReplicant?.lastCheer?.data.amount }} bits by {{
41+
streamElementsReplicant?.lastCheer?.data.displayName }}
42+
</span>
43+
<span v-else>none</span>
44+
</p>
45+
<p>
46+
Last follow:
47+
<span v-if="streamElementsReplicant?.lastFollow">
48+
{{ streamElementsReplicant?.lastFollow?.data.displayName }}
49+
</span>
50+
<span v-else>none</span>
51+
</p>
52+
<p>
53+
Last raid:
54+
<span v-if="streamElementsReplicant?.lastRaid">
55+
{{ streamElementsReplicant?.lastRaid?.data.displayName }} raided with {{
56+
streamElementsReplicant?.lastRaid?.data.amount }} viewers
57+
</span>
58+
<span v-else>none</span>
59+
</p>
60+
<p>
61+
Last host:
62+
<span v-if="streamElementsReplicant?.lastHost">
63+
{{ streamElementsReplicant?.lastHost?.data.displayName }} hosted with {{
64+
streamElementsReplicant?.lastHost?.data.viewers }} viewers
65+
</span>
66+
<span v-else>none</span>
67+
</p>
68+
</div>
69+
70+
<script src="index.js"></script>
71+
</body>
72+
</html>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// <reference types="nodecg-types/types/browser" />
2+
import { createApp, defineComponent } from "vue";
3+
import type { StreamElementsReplicant } from "nodecg-io-streamelements";
4+
5+
const replicant = nodecg.Replicant<StreamElementsReplicant>("streamelements");
6+
7+
const mainComponent = defineComponent<unknown, unknown, { streamElementsReplicant: StreamElementsReplicant }>({
8+
data() {
9+
return {
10+
streamElementsReplicant: {},
11+
};
12+
},
13+
created() {
14+
replicant.on("change", (newVal) => {
15+
this.streamElementsReplicant = newVal;
16+
});
17+
},
18+
computed: {
19+
subTier() {
20+
const sub = this.streamElementsReplicant.lastSubscriber;
21+
if (!sub || !sub.data.tier) return undefined;
22+
23+
if (sub.data.tier === "prime") {
24+
return "Twitch Prime";
25+
}
26+
27+
// We want to display the tier as 1, 2, 3
28+
// However StreamElements stores the sub tiers as 1000, 2000 and 3000.
29+
// So we divide the tier by 1000 to get the tier in our expected format.
30+
const tierLevel = Number.parseInt(sub.data.tier) / 1000;
31+
return `Tier ${tierLevel}`;
32+
},
33+
},
34+
});
35+
36+
createApp(mainComponent).mount("#app");
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"extends": "nodecg-io-tsconfig",
3+
"compilerOptions": {
4+
"target": "ES2015",
5+
"lib": ["ES2015", "dom"],
6+
"module": "ES2015",
7+
"noEmit": true
8+
},
9+
"references": [
10+
{
11+
"path": "../../../nodecg-io-core"
12+
},
13+
{
14+
"path": "../../../services/nodecg-io-streamelements"
15+
}
16+
]
17+
}

samples/streamelements-events/package.json

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,33 @@
22
"name": "streamelements-events",
33
"version": "0.3.0",
44
"private": true,
5+
"scripts": {
6+
"build": "node graphics/esbuild.config.js",
7+
"watch": "npm run build -- --watch"
8+
},
59
"nodecg": {
610
"compatibleRange": "^1.1.1",
711
"bundleDependencies": {
812
"nodecg-io-streamelements": "^0.3.0"
9-
}
13+
},
14+
"graphics": [
15+
{
16+
"file": "index.html",
17+
"width": "1920",
18+
"height": "1080"
19+
}
20+
]
1021
},
1122
"license": "MIT",
1223
"dependencies": {
1324
"@types/node": "^18.0.3",
14-
"nodecg-types": "^1.8.3",
25+
"esbuild": "^0.14.23",
26+
"esbuild-plugin-alias": "^0.2.1",
1527
"nodecg-io-core": "^0.3.0",
1628
"nodecg-io-streamelements": "^0.3.0",
29+
"nodecg-io-tsconfig": "^1.0.0",
30+
"nodecg-types": "^1.8.3",
1731
"typescript": "^4.7.4",
18-
"nodecg-io-tsconfig": "^1.0.0"
32+
"vue": "^3.2.31"
1933
}
2034
}
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
{
2-
"extends": "nodecg-io-tsconfig",
2+
"files": [],
3+
"compilerOptions": {
4+
"composite": true
5+
},
36
"references": [
47
{
5-
"path": "../../nodecg-io-core"
8+
"path": "./extension"
69
},
710
{
8-
"path": "../../services/nodecg-io-streamelements"
11+
"path": "./graphics"
912
}
1013
]
1114
}

services/nodecg-io-serial/extension/SerialClient.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ export interface SerialServiceConfig {
2323

2424
export class SerialServiceClient extends SerialPort {
2525
private parser: ReadlineParser;
26-
constructor(
27-
options: SerialPortOpenOptions<AutoDetectTypes>,
28-
protocol?: ReadlineOptions, // TODO: maybe rename this to parseOptions or something
29-
callback?: ErrorCallback,
30-
) {
26+
constructor(options: SerialPortOpenOptions<AutoDetectTypes>, protocol?: ReadlineOptions, callback?: ErrorCallback) {
3127
super(options, callback);
3228
this.parser = this.pipe(new ReadlineParser(protocol));
3329
}

0 commit comments

Comments
 (0)