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

Add replicant with last events to streamelement service #494

Merged
merged 8 commits into from
Jul 15, 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
6,991 changes: 1,867 additions & 5,124 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 8 additions & 1 deletion samples/streamelements-events/extension/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { NodeCG } from "nodecg-types/types/server";
import { StreamElementsServiceClient } from "nodecg-io-streamelements";
import { StreamElementsReplicant, StreamElementsServiceClient } from "nodecg-io-streamelements";
import { requireService } from "nodecg-io-core";

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

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

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

client.onGift((data) => {
if (data.data.tier) {
// We want to display the tier as 1, 2, 3
// However StreamElements stores the sub tiers as 1000, 2000 and 3000.
// So we divide the tier by 1000 to get the tier in our expected format.
// We don't need to care about prime subs here because they cannot be gifted.
const tier = (Number.parseInt(data.data.tier) / 1000).toString();
if (data.data.sender) {
nodecg.log.info(
Expand Down Expand Up @@ -62,6 +67,8 @@ module.exports = function (nodecg: NodeCG) {
client.onTest((data) => {
nodecg.log.info(JSON.stringify(data));
});

client.setupReplicant(streamElementsReplicant);
});

streamElements?.onUnavailable(() => nodecg.log.info("SE client has been unset."));
Expand Down
11 changes: 11 additions & 0 deletions samples/streamelements-events/extension/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-streamelements"
}
]
}
55 changes: 55 additions & 0 deletions samples/streamelements-events/graphics/esbuild.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// @ts-check
/* eslint-disable @typescript-eslint/no-var-requires */
/* eslint-disable no-undef */
/* eslint-disable no-console */

const esbuild = require("esbuild");
const esbuildAlias = require("esbuild-plugin-alias");
const path = require("path");
const process = require("process");
const fs = require("fs");

const args = new Set(process.argv.slice(2));
const prod = process.env.NODE_ENV === "production";

if (args.has("--clean") || args.has("--rebuild")) {
// Remove dist folder
try {
fs.rmSync(path.join(__dirname, "index.js"));
} catch (error) {
console.log(error);
}

if (!args.has("--rebuild")) {
process.exit(0);
}
}

/** @type {import('esbuild').BuildOptions} */
const BuildOptions = {
bundle: true,
entryPoints: [path.join(__dirname, "index.ts")],
minify: prod,
outfile: path.join(__dirname, "index.js"),
platform: "browser",
sourcemap: true,
watch: args.has("--watch"),
plugins: [
esbuildAlias({
"vue": require.resolve("vue/dist/vue.esm-bundler.js"),
})
]
};

esbuild
.build(BuildOptions)
.catch(() => process.exit(1))
.then((result) => {
if (result.errors.length > 0) {
console.error(result.errors);
}

if (result.warnings.length > 0) {
console.error(result.warnings);
}
});
72 changes: 72 additions & 0 deletions samples/streamelements-events/graphics/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charstreamElementsReplicantt="UTF-8" />
<title>streamelements-events sample bundle</title>
<style>
body {
font-family: sans-streamElementsReplicantrif;
}
/* don't show container until vue has compiled all templates */
[v-cloak] {
display: none;
}
</style>
</head>

<body>
<h1>streamelements-events sample bundle</h1>
<div id="app" v-cloak>
<p>Newest events of configured streamelements instance:</p>
<p>
Last subscriber:
<span v-if="streamElementsReplicant?.lastSubscriber">
{{ streamElementsReplicant?.lastSubscriber?.data.displayName }} subscribed for {{
streamElementsReplicant?.lastSubscriber?.data.amount }} months ({{ subTier }}).
</span>
<span v-else>none</span>
</p>
<p>
Last tip:
<span v-if="streamElementsReplicant?.lastTip">
{{ streamElementsReplicant?.lastSubscriber?.data.displayName }} subscribed for {{
streamElementsReplicant?.lastSubscriber?.data.amount }} months.
</span>
<span v-else>none</span>
</p>
<p>
Last cheer:
<span v-if="streamElementsReplicant?.lastCheer">
{{ streamElementsReplicant?.lastCheer?.data.amount }} bits by {{
streamElementsReplicant?.lastCheer?.data.displayName }}
</span>
<span v-else>none</span>
</p>
<p>
Last follow:
<span v-if="streamElementsReplicant?.lastFollow">
{{ streamElementsReplicant?.lastFollow?.data.displayName }}
</span>
<span v-else>none</span>
</p>
<p>
Last raid:
<span v-if="streamElementsReplicant?.lastRaid">
{{ streamElementsReplicant?.lastRaid?.data.displayName }} raided with {{
streamElementsReplicant?.lastRaid?.data.amount }} viewers
</span>
<span v-else>none</span>
</p>
<p>
Last host:
<span v-if="streamElementsReplicant?.lastHost">
{{ streamElementsReplicant?.lastHost?.data.displayName }} hosted with {{
streamElementsReplicant?.lastHost?.data.viewers }} viewers
</span>
<span v-else>none</span>
</p>
</div>

<script src="index.js"></script>
</body>
</html>
36 changes: 36 additions & 0 deletions samples/streamelements-events/graphics/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/// <reference types="nodecg-types/types/browser" />
import { createApp, defineComponent } from "vue";
import type { StreamElementsReplicant } from "nodecg-io-streamelements";

const replicant = nodecg.Replicant<StreamElementsReplicant>("streamelements");

const mainComponent = defineComponent<unknown, unknown, { streamElementsReplicant: StreamElementsReplicant }>({
data() {
return {
streamElementsReplicant: {},
};
},
created() {
replicant.on("change", (newVal) => {
this.streamElementsReplicant = newVal;
});
},
computed: {
subTier() {
const sub = this.streamElementsReplicant.lastSubscriber;
if (!sub || !sub.data.tier) return undefined;

if (sub.data.tier === "prime") {
return "Twitch Prime";
}

// We want to display the tier as 1, 2, 3
// However StreamElements stores the sub tiers as 1000, 2000 and 3000.
// So we divide the tier by 1000 to get the tier in our expected format.
const tierLevel = Number.parseInt(sub.data.tier) / 1000;
return `Tier ${tierLevel}`;
},
},
});

createApp(mainComponent).mount("#app");
17 changes: 17 additions & 0 deletions samples/streamelements-events/graphics/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "nodecg-io-tsconfig",
"compilerOptions": {
"target": "ES2015",
"lib": ["ES2015", "dom"],
"module": "ES2015",
"noEmit": true
},
"references": [
{
"path": "../../../nodecg-io-core"
},
{
"path": "../../../services/nodecg-io-streamelements"
}
]
}
20 changes: 17 additions & 3 deletions samples/streamelements-events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,33 @@
"name": "streamelements-events",
"version": "0.3.0",
"private": true,
"scripts": {
"build": "node graphics/esbuild.config.js",
"watch": "npm run build -- --watch"
},
"nodecg": {
"compatibleRange": "^1.1.1",
"bundleDependencies": {
"nodecg-io-streamelements": "^0.3.0"
}
},
"graphics": [
{
"file": "index.html",
"width": "1920",
"height": "1080"
}
]
},
"license": "MIT",
"dependencies": {
"@types/node": "^18.0.3",
"nodecg-types": "^1.8.3",
"esbuild": "^0.14.23",
"esbuild-plugin-alias": "^0.2.1",
"nodecg-io-core": "^0.3.0",
"nodecg-io-streamelements": "^0.3.0",
"nodecg-io-tsconfig": "^1.0.0",
"nodecg-types": "^1.8.3",
"typescript": "^4.7.4",
"nodecg-io-tsconfig": "^1.0.0"
"vue": "^3.2.31"
}
}
9 changes: 6 additions & 3 deletions samples/streamelements-events/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
{
"extends": "nodecg-io-tsconfig",
"files": [],
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "../../nodecg-io-core"
"path": "./extension"
},
{
"path": "../../services/nodecg-io-streamelements"
"path": "./graphics"
}
]
}
6 changes: 1 addition & 5 deletions services/nodecg-io-serial/extension/SerialClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,7 @@ export interface SerialServiceConfig {

export class SerialServiceClient extends SerialPort {
private parser: ReadlineParser;
constructor(
options: SerialPortOpenOptions<AutoDetectTypes>,
protocol?: ReadlineOptions, // TODO: maybe rename this to parseOptions or something
callback?: ErrorCallback,
) {
constructor(options: SerialPortOpenOptions<AutoDetectTypes>, protocol?: ReadlineOptions, callback?: ErrorCallback) {
super(options, callback);
this.parser = this.pipe(new ReadlineParser(protocol));
}
Expand Down
25 changes: 25 additions & 0 deletions services/nodecg-io-streamelements/extension/StreamElements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ import io = require("socket.io-client");
import { Result, emptySuccess, error } from "nodecg-io-core";
import { StreamElementsEvent } from "./StreamElementsEvent";
import { EventEmitter } from "events";
import { Replicant } from "nodecg-types/types/server";

export interface StreamElementsReplicant {
lastSubscriber?: StreamElementsEvent;
lastTip?: StreamElementsEvent;
lastCheer?: StreamElementsEvent;
lastGift?: StreamElementsEvent;
lastFollow?: StreamElementsEvent;
lastRaid?: StreamElementsEvent;
lastHost?: StreamElementsEvent;
}

export class StreamElementsServiceClient extends EventEmitter {
private socket: SocketIOClient.Socket;
Expand Down Expand Up @@ -131,4 +142,18 @@ export class StreamElementsServiceClient extends EventEmitter {
public onTest(handler: (data: StreamElementsEvent) => void): void {
this.on("test", handler);
}

public setupReplicant(rep: Replicant<StreamElementsReplicant>): void {
if (rep.value === undefined) {
rep.value = {};
}

this.on("subscriber", (data) => (rep.value.lastSubscriber = data));
this.on("tip", (data) => (rep.value.lastTip = data));
this.on("cheer", (data) => (rep.value.lastCheer = data));
this.on("gift", (data) => (rep.value.lastGift = data));
this.on("follow", (data) => (rep.value.lastFollow = data));
this.on("raid", (data) => (rep.value.lastRaid = data));
this.on("host", (data) => (rep.value.lastHost = data));
}
}
2 changes: 1 addition & 1 deletion services/nodecg-io-streamelements/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface StreamElementsServiceConfig {
handleTestEvents: boolean;
}

export { StreamElementsServiceClient } from "./StreamElements";
export { StreamElementsServiceClient, StreamElementsReplicant } from "./StreamElements";

module.exports = (nodecg: NodeCG) => {
const schemaPath = [__dirname, "../streamelements-schema.json"];
Expand Down